Цель этой статьи — помочь разработчику Android быстро освоить язык программирования Swift. (Пишу с этой точки зрения.)
Я не собирался писать очень длинную и подробную статью, чтобы охватить все, просто быстрая статья для того, чтобы вы освоились.
Эта статья также подходит для:
- Опытный программист (знающий другие языки программирования) хочет изучить Swift.
- iOS-разработчик (знающий Swift) хочет изучить Kotlin.
- Начинающих разработчиков iOS.
- Разработчик давно не использовал Swift и хочет получить краткую памятку.
Основные типы
Swift | Kotlin |
---|---|
Bool | Boolean |
Массив | Массив, Список, MutableList |
Набор | Набор |
Словарь | Map |
Другие типы в основном такие же.
Синтаксис
Swift | Kotlin | |
---|---|---|
переменные (не полностью равнозначны, см. пояснения ниже) | let/var | val/var |
именованные аргументы | в: 0 | at = 0 |
функция | func name() → returnType | fun name(): returnType |
отсутствие значения | nil | нуль |
развёрнутый тип | Строка! | — |
если | если число != nil | if(number != null) |
предоставьте значение по умолчанию, если nil или null | xxx ?? «строка по умолчанию» | ? : «строка по умолчанию» |
если значение есть, сделайте {} | if let number = Int(«333») {} | ?.let {} |
for loop | for i in 1…5 {} | for (i in 1..5) {} |
for loop | for i in 1…<5 {} | for (i in 1 until 5) {} |
do while loop | повторять {} while | do {} while () |
данный экземпляр | self | этот |
объект значения | структура | класс данных |
как? | как? | |
как! | as | |
попробовать? | — | |
попробовать! | — | |
инициализатор класса | инициализатор | конструктор |
инициализация изменяемого списка | var someInts: [Int] = [] | val someInts = mutableListOf() |
инициализация пустого словаря/карты | var namesOfIntegers: [Int: String] = [:] | val namesOfIntegers = mutableMapOf() |
Константы и переменные
Swift:
Kotlin:
- Неизменяемость или изменяемость типов коллекций контролируется типом данных.
Случай Switch
Swift:
var x = 3
switch x {
case 1: print("x == 1")
case 2, 4: print("x == 2 or x == 4")
default: print("x is something else")
}
Kotlin:
val x = 3
when (x) {
1 -> print("x == 1")
2, 4 -> print("x == 2 or x == 4")
else -> print("x is something else")
}
Интерполяция строк
Swift:
var name = "Mike"
print("Hello (name)")
Строка также может быть выведена в формате:
let str = NSString(format:"%d , %f, %ld, %@", 1, 1.5, 100, "Hello World")
print(str)
Kotlin:
var name = "Mike"
println("Hello $name")
val str = String.format("%d, %f, %d, %s", 1, 1.5, 100, "Hello World")
print(str)
Функция и закрытие
Функция Swift имеет метку аргумента:
func someFunction(argumentLabel parameterName: Int) {
// In the function body, parameterName refers to the argument value
// for that parameter.
}
В то время как parameterName
используется внутри функции, argumentLabel
используется вызывающей стороной.
Если метка аргумента не указана, parameterName также играет роль метки аргумента.
Если вы не хотите указывать метку аргумента вообще, ее можно опустить, используя символ подчеркивания _
.
Closure
Closure похож на лямбду в Kotlin.
Простой пример на Swift:
let sayHello = { (name: String) -> String in
let result = "Hello (name)"
print(result)
return result
}
sayHello("Mike")
Сделайте то же самое в Kotlin:
val sayHello : (String) -> String = { name: String ->
val result = "Hello $name"
print(result)
result
}
sayHello("Mike")
Общие:
- Тип может быть выведен из контекста.
- Может передаваться в качестве аргументов как параметр другой функции для получения вложенных функций (функций высокого порядка).
- Если замыкание/лямбда является последним параметром, мы можем поместить его за скобки функции. если это единственный параметр, нам не нужно писать parentheses().
Различия:
- В Swift только закрытие одного выражения может опускать ключевое слово
return
; в Kotlin последнее выражение будет рассматриваться как возвращаемое значение, ключевое слово return в лямбде отсутствует. - В Swift есть сокращенные имена аргументов, такие как
$0
,$1
,$2
.
Пользовательские типы
Swift | Kotlin |
---|---|
класс | класс |
протокол | интерфейс |
расширение | методы расширения |
класс
Класс в Swift и Kotlin выглядит совершенно одинаково.
Для наследования используется :
, а функция подкласса может переопределять
функцию суперкласса.
Существует требование порядка: класс должен быть помещен перед любыми протоколами.
Единственное, что отличается — это конструктор, в swift это инициализатор:
class Person {
let name: String
init(name: String = "") {
self.name = name
}
}
let p1 = Person()
print("(p1.name)") // default name: ""
let p2 = Person(name: "haha")
print("(p2.name)")
В Kotlin мы могли бы достичь того же результата, написав так:
class Person(val name: String = "") {
}
val p1 = Person()
print("${p1.name}") // default name: ""
val p2 = Person(name="haha")
print("${p2.name}")
struct
Структура — это тип значения.
struct отличается от класса:
- класс может наследоваться.
- struct — тип значения, копии никогда не делятся данными; class — ссылочный тип, все копии будут иметь один и тот же экземпляр.
- класс имеет
deinit
. - экземпляр класса может быть
let
, и вы можете изменить свойствоvar
класса.
class Person {
var name = "Lily"
}
let p1 = Person()
p1.name = "Justin"
print("(p1.name)")
Это нормально.
Но если Person является структурой:
struct Person {
var name = "Lily"
}
let p1 = Person()
p1.name = "Justin"
// Compiler error: Cannot assign to property: `p1` is a `let` constant
При использовании struct, мы должны использовать **var** p1 = Person()
.
протокол
Протокол — это то же самое, что interface
в Kotlin.
Мы можем определить функцию и свойства как контракты.
Свойствами могут быть:
protocol SomeProtocol {
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
}
Есть небольшие различия между протоколом и интерфейсом, например, классу, реализующему протокол, не нужно использовать ключевое слово override
в функциях.
расширение
Расширение также отличается. В Swift расширение больше похоже на место для хранения функций и свойств.
extension String {
func trimmed() -> String {
self.trimmingCharacters(in: .whitespacesAndNewlines)
}
mutating func trim() {
self = self.trimmed()
}
var lines: [String] {
self.components(separatedBy: .newlines)
}
}
В Kotlin метод расширения может быть методом верхнего уровня, просто добавьте тип перед .
:
fun String.someMethod() : String {
return this.trim()
}
enum
Swift enum:
enum CompassPoint {
case north
case south
case east
case west
}
Несколько случаев могут быть помещены в одну строку, разделенные запятой:
enum Planet {
case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}
При использовании перечисления мы можем опустить тип, используя более короткий синтаксис с точкой:
var directionToHead = CompassPoint.west
directionToHead = .east
Swift enum имеет свойство allCases
, которое раскрывает коллекцию всех случаев.
Kotlin:
enum class Direction {
NORTH, SOUTH, WEST, EAST
}
В enum мы также можем определять свойства и функции, что одинаково для Swift и Kotlin.
Опции
Хотя синтаксис опционального типа в Swift и типа nullable в Kotlin выглядит похоже (вопросительный знак после типа), они отличаются.
Опциональный тип в Swift больше похож на Optional
в Java.
Вам всегда нужно развернуть его перед использованием значения.
var someString : String? = nil
print(someString?.count) // print nil
print(someString!.count) // Fatal error: Unexpectedly found nil while unwrapping an Optional value
Когда переменная имеет значение, мы хотим его использовать:
var someString : String? = "Hello"
if (someString != nil) {
print("(someString) with length (someString?.count)")
// print: Optional("Hello") with length Optional(5)
print("(someString!) with length (someString!.count)")
// print: Hello with length 5
}
Обратите внимание, что при прямом использовании переменная всегда будет Optional.
На самом деле в Swift есть более простой способ сделать это, используя if let
:
if let someStringValue = someString {
print("(someStringValue) with length (someStringValue.count)")
}
someStringValue
— это развернутое значение из someString
, и блок вводится только тогда, когда оно не nil
.
В Kotlin:
var someString : String? = null
print(someString?.length) // print null
print(someString!!.length) // NullPointerException
Разница в основном в том, когда переменная имеет значение:
var someString : String? = "Hello"
if(someString != null) {
print("$someString with length: ${someString.length}")
}
// print: Hello with length: 5
В Kotlin, после проверки того, что переменная не является нулевой, мы можем использовать значение напрямую, в следующем коде внутри {}
, компилятор знает, что переменная не является нулевой.
If let и guard let
Как мы видим в примере выше в разделе Optional, if let
может развернуть значение Optional и выполнить блок только тогда, когда оно имеет значение.
А guard let
делает обратное: блок else
будет введен только тогда, когда значение равно nil
.
func printSquare(of number: Int?){
guard let number = number else {
print("Oops we got nil")
return
}
print("(number) * (number) is (number * number)")
}
guard let может быть использован для проверки аргументов и раннего возврата.
После guard let число больше не является необязательным, оно имеет значение.
Последнее замечание
Я не советую тратить много времени на детальное изучение синтаксиса языка.
Просто возьмите некоторые основы, и вы готовы к работе, больше вы узнаете в процессе повседневной работы.
В любом случае, я надеюсь, что эта статья будет для вас полезной и нужной.
Ссылки
- Книга по Swift: https://docs.swift.org/swift-book/