Swift和Kotlin作为更加"现代化"的语言,毫无疑问提升了开发原生app的效率,二者旨在与Objective-C和Java互操作,方便"旧"应用的开发进行更新,如果你要从零开始编写一个全新的应用,不要犹豫,选择使用它们,尽情享受它们带来的乐趣。这两个语言有着许多相似之处,让我们来"欣赏"一下吧:
语法差异
print("Hello, world!") //Swift
println("Hello, world!") //Kotlin
变量和常量
var myVariable = 42 //Swift
myVariable = 50
let myConstant = 42
var myVariable = 42 //Kotlin
myVariable = 50
val myConstant = 42
显示声明
let explicitDouble: Double = 70 //Swift
val explicitDouble: Double = 70.0 //Kotlin
隐式声明
let label = "The width is " //Swift
let width = 94
let widthLabel = label + String(width)
val label = "The width is " //Kotlin
val width = 94
val widthLabel = label + width
字符串插值
let apples = 3 //Swift
let oranges = 5
let fruitSummary = "I have \(apples + oranges) " + "pieces of fruit."
val apples = 3 //Kotlin
val oranges = 5
val fruitSummary = "I have ${apples + oranges} " + "pieces of fruit."
可选类型
var str: String? //Swift
var str: String? //Kotlin
判空
if str != nil { //Swift
print("\(str)")
}
//推荐使用
if let str = str {
print("\(str)")
}
if (str != null) { //Kotlin
println("$str")
}
//推荐使用
str?.let {
println("$str")
}
guard
guard let str = str else { //Swift
//do something
}
val id = str ?: run { //Kotlin
//do something
}
可选链式调用
let length = str?.count //Swift
val length = str?.length //Kotlin
强制解析
let length = str!.count //Swift
val length = str!!.length //Kotlin
空合运算符
let length = str?.count ?? 0 //Swift
val length = str?.length ?: 0 //Kotlin
半开区间运算符
let names = ["Anna", "Alex", "Brian", "Jack"] //Swift
let count = names.count
for i in 0..<count {
print("Person \(i + 1) is called \(names[i])")
}
val names = arrayOf("Anna", "Alex", "Brian", "Jack")//Kotlin
val count = names.count()
for (i in 0 until count) {
println("Person ${i + 1} is called ${names[i]}")
}
闭区间运算符
for index in 1...5 { //Swift
print("\(index) times 5 is \(index * 5)")
}
for (index in 1..5) { //Kotlin
println("$index times 5 is ${index * 5}")
}
数组
var shoppingList = ["catfish", "water", //Swift
"tulips", "blue paint"]
shoppingList[1] = "bottle of water"
val shoppingList = arrayOf("catfish", "water", //Kotlin
"tulips", "blue paint")
shoppingList[1] = "bottle of water"
字典
var occupations = [ //Swift
"Malcolm": "Captain",
"Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"
val occupations = mutableMapOf( //Kotlin
"Malcolm" to "Captain",
"Kaylee" to "Mechanic"
)
occupations["Jayne"] = "Public Relations"
空集
let emptyArray = [String]() //Swift
let emptyDictionary = [String: Float]()
val emptyArray = arrayOf<String>() //Kotlin
val emptyMap = mapOf<String, Float>()
函数
func greet(_ name: String,_ day: String) -> String {//Swift
return "Hello \(name), today is \(day)."
}
greet("Bob", "Tuesday")
fun greet(name: String, day: String): String { //Kotlin
return "Hello $name, today is $day."
}
greet("Bob", "Tuesday")
元组
func getGasPrices() -> (Double, Double, Double) { //Swift
return (3.59, 3.69, 3.79)
}
data class GasPrices(val a: Double, val b: Double, //Kotlin
val c: Double)
fun getGasPrices() = GasPrices(3.59, 3.69, 3.79)
可变参数
func sumOf(_ numbers: Int...) -> Int { //Swift
var sum = 0
for number in numbers {
sum += number
}
return sum
}
sumOf(42, 597, 12)
fun sumOf(vararg numbers: Int): Int { //Kotlin
var sum = 0
for (number in numbers) {
sum += number
}
return sum
}
sumOf(42, 597, 12)
// sumOf() can also be written in a shorter way:
fun sumOf(vararg numbers: Int) = numbers.sum()
函数类型
func makeIncrementer() -> (Int -> Int) { //Swift
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
let increment = makeIncrementer()
increment(7)
fun makeIncrementer(): (Int) -> Int { //Kotlin
val addOne = fun(number: Int): Int {
return 1 + number
}
return addOne
}
val increment = makeIncrementer()
increment(7)
// makeIncrementer can also be written in a shorter way:
fun makeIncrementer() = fun(number: Int) = 1 + number
参数名称
func area(width: Int, height: Int) -> Int { //Swift
return width * height
}
area(width: 2, height: 3)
fun area(width: Int, height: Int) = width * height //Kotlin
area(width = 2, height = 3)
// This is also possible with named arguments
area(2, height = 2)
area(height = 3, width = 2)
声明类
class Shape { //Swift
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
class Shape { //Kotlin
var numberOfSides = 0
fun simpleDescription() : String {
return "A shape with $numberOfSides sides."
}
}
使用类
var shape = Shape() //Swift
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
var shape = Shape() //Kotlin
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
懒加载
lazy var shape = Shape() //Swift
val shape by lazy {Shape()} //Kotlin
子类
class NamedShape { //Swift
var numberOfSides: Int = 0
let name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
class Square: NamedShape {
private var sideLength: Double
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
self.numberOfSides = 4
}
func area() -> Double {
return sideLength * sideLength
}
override func simpleDescription() -> String {
return "A square with sides of length " + String(sideLength) + "."
}
}
let test = Square(sideLength: 5.2, name: "square")
test.area()
test.simpleDescription()
open class NamedShape(val name: String) { //Kotlin
var numberOfSides = 0
open fun simpleDescription() =
"A shape with $numberOfSides sides."
}
class Square(private var sideLength: BigDecimal, name: String) :
NamedShape(name) {
init {
numberOfSides = 4
}
fun area() = sideLength.pow(2)
override fun simpleDescription() =
"A square with sides of length $sideLength."
}
val test = Square(BigDecimal("5.2"), "square")
test.area()
test.simpleDescription()
类型检查
var movieCount = 0 //Swift
var songCount = 0
for item in library {
if item is Movie {
movieCount += 1
} else if item is Song {
songCount += 1
}
}
var movieCount = 0 //Kotlin
var songCount = 0
for (item in library) {
if (item is Movie) {
++movieCount
} else if (item is Song) {
++songCount
}
}
模式匹配
let nb = 42 //Swift
switch nb {
case 0...7, 8, 9: print("single digit")
case 10: print("double digits")
case 11...99: print("double digits")
case 100...999: print("triple digits")
default: print("four or more digits")
}
val nb = 42 //Kotlin
when (nb) {
in 0..7, 8, 9 -> println("single digit")
10 -> println("double digits")
in 11..99 -> println("double digits")
in 100..999 -> println("triple digits")
else -> println("four or more digits")
}
向下转型
for current in someObjects { //Swift
if let movie = current as? Movie {
print("Movie: '\(movie.name)', " +
"dir. \(movie.director)")
}
}
for (current in someObjects) { //Kotlin
if (current is Movie) {
println("Movie: '${current.name}', " +
"dir. ${current.director}")
}
}
协议
protocol Nameable { //Swift
func name() -> String
}
func f<T: Nameable>(x: T) {
print("Name is " + x.name())
}
interface Nameable { //Kotlin
fun name(): String
}
fun <T: Nameable> f(x: T) {
println("Name is " + x.name())
}
扩展
extension Double { //Swift
var km: Double { return self * 1_000.0 }
var m: Double { return self }
var cm: Double { return self / 100.0 }
var mm: Double { return self / 1_000.0 }
var ft: Double { return self / 3.28084 }
}
let oneInch = 25.4.mm
print("One inch is \(oneInch) meters")
// prints "One inch is 0.0254 meters"
let threeFeet = 3.ft
print("Three feet is \(threeFeet) meters")
val Double.km: Double get() = this * 1000 //Kotlin
val Double.m: Double get() = this
val Double.cm: Double get() = this / 100
val Double.mm: Double get() = this / 1000
val Double.ft: Double get() = this / 3.28084
val oneInch = 25.4.mm
println("One inch is $oneInch meters")
// prints "One inch is 0.0254 meters"
val threeFeet = 3.0.ft
println("Three feet is $threeFeet meters")
// prints "Three feet is 0.914399970739201 meters"
其他区别
Kotlin数据类
Kotlin有一个称为数据类的东西,该类在编译时将获得诸如hashCode(),toString()和copy()等方法。可以这样定义:
data class SampleClass(var a: Int = 0, var b: Int = 0, var c: String = "")
Swift没有数据类或任何等效类。
元组
Swift具有元组功能,并且可以为元组设定类型别名;
Kotlin具有Pair和Triple工具类,用于呈现2元和3元组对象,并且可以通过data class模拟自定义元组。
//Swift
typealias SampleTuple = (var1: String, var2: String, var3: String)
//Kotlin
data class SampleTuple(val var1: String, val var2: String, val var3: String)
// Definition of Pair data class Pair<out A, out B>
// Definition of Triple data class Triple<out A, out B, out C>
Swift结构体
Swift Struct和Class之间的区别在于,结构体是值类型,而类是引用类型。可将元组视为隐式定义的Struct:
struct SampleStruct {
var a: Int = 0
var b: Int = 0
var c: String = ""
}
Kotlin没有Struct类型。但是,我们可以通过copy函数创建一个新引用:
val sample = SampleClass(1, 1, "Sample")
val newSample = sample.copy()
我们可以使用Kotlin数据类和Swift结构体来保存数据。即使一个是引用类型,另一个是值类型。
枚举和密封类
Swift和Kotlin都有枚举。但是声明和匹配方式有很大的区别:
enum Game { //Swift
case regular
case baseball(Int, String)
case football(Int, Int, String)
case basketball(Int, String)
}
func playGame(game: Game) -> Void {
switch game {
case .regular:
print("")
case .baseball(let inning, let count):
print("\(inning)) \(count)")
case .football(let down, let yardsToGo, let timeLeft):
print("\(down)) \(yardsToGo) \(timeLeft)")
case .basketball(let quarter, let timeLeft):
print("\(quarter)) \(timeLeft)")
}
}
Kotlint通过密封类可以实现枚举。Kotlin的Sealed Class和Swift的Enum之间的唯一区别是,密封类是引用类型,而Swift的Enum是值类型:
sealed class Game { //Kotlin
object RegularGame: Game()
class BaseballGame(val inning: Int, val count: String): Game()
class FootballGame(val down: Int, val yardsToGo: Int, val timeLeft: String): Game()
class BasketballGame(val quarter: Int, val timeLeft: String): Game()
}
fun playGame(game: Game) {
when(game) {
is RegularGame -> println("")
is BaseballGame -> println("")
is FootballGame -> println("")
is BasketballGame -> println("")
}
}
隐式解包vs lateinit
Swift还具有隐式解包功能,它定义了一个可选内容,但告诉编译器可以展开该内容,因为后面它将会被值。Kotlin也可以通过lateinit关键字执行相同的操作。需要注意的是,作为开发人员,应尽可能避免使用隐式解包方式。
var string: String! //Swift
func doBadStuff() {
string.doSomething() // Will crash because string doesn’t have a value
}
---------------------
string = “String”
func doGoodStuff() {
string.doSomething() // This is good because string was set.
}
lateinit var string: String //Kotlin
fun doBadStuff() {
string.doSomething() // Will crash because string doesn’t have a value
}
---------------
string = "String"
fun doGoodStuff() {
string.doSomething() // This is good because string was set.
}
协议和接口
协议和接口有相同的功能,只是使用了不同的术语。它们定义了一个类在实现接口时必须遵循的一组函数/变量。Kotlin允许在接口的定义中使用泛型,而Swift则可以通过定义关联类型associatedtype来实现。
protocol SampleProtocol { //Swift
associatedtype T
func get(value: T) -> T
}
extension SampleProtocol where Self.T == Self {
func get(value: Self) -> Self {
// do stuff
}
}
struct SomeClass: SampleProtocol {
func get(value: SomeClass) -> SomeClass {
// do stuff
}
}
interface SampleInterface<T> { //Kotlin
fun get(value: T): T {
// do stuff
}
}
class SomeClass: SampleInterface<Int> {
override fun get(value: Int): Int {
// do stuff
}
}
高阶函数
高阶函数本质上是接受闭包或函数作为参数并返回新值或另一个函数的函数。使用高阶函数,我们可以对值(例如数组)进行转换,过滤和迭代。
func higherOrderFunctions() { //Swift
let array = [1,2,3,4,5,6,7,8,9,10]
// $0 is implicitly defined as the current value of the spot you are at in an array
let mappedArray = array.map {
$0 * 2
}
let filteredArray = array.filter {
$0 % 2 == 0
}
// $0 is not an option because the current value in the closure is now defined as (acc, element)
let reducedArray = array.reduce(0) { (acc, element) in
return acc + element
}
}
fun higherOrderFunctions() { //Kotlin
val array = arrayOf(1,2,3,4,5,6,7,8,9,10)
// it is implicitly defined as the value of the spot you are at in an array
val mappedArray = array.map {
it * 2
}
// result: [2,4,6,8,10,12,14,16,18,20]
val filteredArray = array.filter {
it % 2 == 0
}
// result: [2,4,6,8,10]
// it is not an option because the current value in the closure is now defined as acc, element
val reducedArray = array.reduce { acc, element ->
acc + element
}
// result: 55
}
参考:
- http://nilhcem.com/swift-is-like-kotlin/
- https://willowtreeapps.com/ideas/swift-and-kotlin-the-subtle-differences
网友评论