[Android开发学iOS系列] 语言篇: Swift vs Kotlin
Swift vs Kotlin
这篇文章是想着帮助Android开发快速学习Swift编程语言用的. (因为这个文章的作者立场就是这样.)
我不想写一个非常长, 非常详尽的文章, 只是想写一个快速的版本能让你快速上手工作.
当然这个文章可能也适合于以下人群:
- 有经验的其他任何语言的开发者, 想学Swift.
- 一个会Swift的iOS开发者, 想横向对比, 了解学习一下Kotlin.
- iOS初级程序员, 刚开始学习.
- 用过Swift, 但是有一阵子没用了, 想快速刷新一下回忆.
基本类型
Swift | Kotlin |
---|---|
Bool | Boolean |
Array | Array, List, MutableList |
Set | Set |
Dictionary | Map |
其他基本类型都是差不多的.
语法
Swift | Kotlin | |
---|---|---|
变量声明 | let/var | val/var |
具名参数 | at: 0 | at = 0 |
函数/方法 | func name() → returnType | fun name(): returnType |
表达无值 | nil | null |
unwrapped type | String! | - |
if | if number != nil | if(number != null) |
为空时提供默认值 | xxx ?? “default string” | ? : ”default string” |
不为空时做某件事 | 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 | repeat {} while | do {} while () |
this instance | self | this |
value object | struct | data class |
as? | as? | |
as! | as | |
try? | - | |
try! | - | |
class initializer | initializer | constructor |
init a mutable list | var someInts: [Int] = [] | val someInts = mutableListOf() |
init a empty dictionary/map | var namesOfIntegers: [Int: String] = [:] | val namesOfIntegers = mutableMapOf<Int, String>() |
Constants and Variables
Swift:
let
不能再次赋值. 如果对象类型是struct
, 不能更新对象的任何字段. 如果是class
, 则仍可更新对象的var
字段.var
可以给变量重新赋值, 也可以更新变量的var
字段.var
可以声明一个mutable的集合类型.
Kotlin:
val
和java中的final
等价, 不能再给变量重新赋值, 但是仍然可以更新对象的var
字段.var
意味着可以给变量重新赋值.- 集合类型的可变与否是被具体的集合类型声明所决定的.
Switch case
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")
}
String interpolation
Swift:
var name = "Mike"
print("Hello \(name)")
也可以给String规定格式:
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)
Function and Closure
Swift的function有一个argument label
:
func someFunction(argumentLabel parameterName: Int) {
// In the function body, parameterName refers to the argument value
// for that parameter.
}
这里parameterName
是方法内部使用的, argumentLabel
是被外部调用者使用的. (目的是为了增强可读性.)
当argument label没有提供的时候, parameter name同时也扮演argument label的角色.
在方法调用时argument label 默认是不能省略的(虽然有时候它和parameter name一样), 如果你想在调用的时候省略, 可以用下划线_
明确指明.
Closure
闭包和Kotlin中的lambda相似.
一个简单的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")
相同点:
- 可以根据上下文推断类型, 所以有时候类型可以省略.
- 可以作为另一个函数的参数传入, 从而实现高阶方法.
- 如果闭包/lambda是方法的最后一个参数, 可以提到圆括号外面. 如果是唯一的参数, 可以省略圆括号.
不同点:
- 在Swift中,只有单句表达式可以省略
return
关键字, 把表达式结果作为返回值. 而在Kotlin中, 最后的表达式值会被作为返回结果, 且在lambda中没有return
关键字. - Swift有缩略版本的参数名, 比如:
$0
,$1
,$2
.
Custom types
Swift | Kotlin |
---|---|
class | class |
protocol | interface |
extension | extension methods |
class
Swift和Kotlin中的类定义和用法十分相似.
继承是通过:
符号, 子类可以override
父类的方法.
继承的的时候父类class需要放在protocol前.
只有构造看起来有点不同, 在Swift中叫initializer:
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的区别:
- class可以继承.
- struct是值类型: 拷贝多份不会共享数据; class是引用类型, 所有的赋值拷贝最终都指向同一份数据实例.
- class有
deinit
. - class的实例可以被
let
保存, 同时实例的var
字段仍然可被修改, struct则不可修改.
class Person {
var name = "Lily"
}
let p1 = Person()
p1.name = "Justin"
print("\(p1.name)")
这是ok的.
如果Person
是struct:
struct Person {
var name = "Lily"
}
let p1 = Person()
p1.name = "Justin"
// Compiler error: Cannot assign to property: `p1` is a `let` constant
编译器会报错.
想要改变字段值, 只能声明: **var** p1 = Person()
.
protocol
protocol类似Kotlin中的interface
.
我们可以定义一些方法或者计算属性作为契约.
Properties写起来是这样的:
protocol SomeProtocol {
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
}
protocol和interface有一点点小区别: 比如实现protocol的类的方法上不需要使用override
关键字.
extension
在Swift, extension更像是一个用来放扩展方法和属性的地方.
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
}
多个case也可以写在一行, 用逗号分隔:
enum Planet {
case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}
在Swift中使用枚举的时候, 我们可以省略前面的类型, 只用一个.
开头:
var directionToHead = CompassPoint.west
directionToHead = .east
Swift enum有一个allCases
属性, 暴露所有case的集合.
Kotlin:
enum class Direction {
NORTH, SOUTH, WEST, EAST
}
在枚举中我们也可以定义方法和属性, 这个Swift和Kotlin是一样的.
Optionals
虽然Swift的optional type和Kotlin的nullable type看起来是类似的(都是具体类型后面加个问号), 但实际上它们还是有点不同.
Swift的optional type更像Java的Optional
.
因为你在用之前永远需要解包(unwrap).
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
解包过的值, 后面的block只有当它不为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中, 如果我们判断过变量不为null, 后面就可以直接用了, 编译器知道这个变量现在不为空了.
if let 和 guard let
我们上面的例子用if let
解包Optional, 只在不为nil的时候执行大括号里面的内容.
guard let
做的事情正好相反: else
block只在值为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
通常被用来做参数检测, 不合法就return.
并且在guard语句之后, number不再是一个optional的类型, 是一个确定有值的类型.
最后
学习新的语言的时候, 不太建议花太多的时间钻研语言的每个细节.
只需要了解一些最基本的知识, 然后就可以上手做具体的工作和任务.
在实际的任务中进行进一步的学习和练习.
总之, 希望这篇文章对你有用.
References
- Swift book: https://docs.swift.org/swift-book/
[Android开发学iOS系列] 语言篇: Swift vs Kotlin的更多相关文章
- [Android开发学iOS系列] 工具篇: Xcode使用和快捷键
[Android开发学iOS系列] 工具篇: Xcode使用和快捷键 工欲善其事必先利其器. 编辑 Cmd + N: 新建文件 Option + Cmd + N: 新建文件夹 Cmd + / : 注释 ...
- [Android开发学iOS系列] iOS写UI的几种方式
[Android开发学iOS系列] iOS写UI的几种方式 作为一个现代化的平台, iOS的发展也经历了好几个时代. 本文讲讲iOS写UI的几种主要方式和各自的特点. iOS写UI的方式 在iOS中写 ...
- [Android开发学iOS系列] Auto Layout
[Android开发学iOS系列] Auto Layout 内容: 介绍什么是Auto Layout. 基本使用方法 在代码中写约束的方法 Auto Layout的原理 尺寸和优先级 Auto Lay ...
- [Android开发学iOS系列] 快速上手UIKit
快速上手iOS UIKit UIKit是苹果官方的framework, 其中包含了各种UI组件, window和view, 事件处理, 交互, 动画, 资源管理等基础设施支持. 按照前面的介绍, 用U ...
- [Android开发学iOS系列] ViewController
iOS ViewController 写UIKit的代码, ViewController是离不开的. 本文试图讲讲它的基本知识, 不是很深入且有点杂乱, 供初级选手和跨技术栈同学参考. What is ...
- iOS系列 基础篇 03 探究应用生命周期
iOS系列 基础篇 03 探究应用生命周期 目录: 1. 非运行状态 - 应用启动场景 2. 点击Home键 - 应用退出场景 3. 挂起重新运行场景 4. 内存清除 - 应用终止场景 5. 结尾 本 ...
- iOS系列 基础篇 05 视图鼻祖 - UIView
iOS系列 基础篇 05 视图鼻祖 - UIView 目录: UIView“家族” 应用界面的构建层次 视图分类 最后 在Cocoa和Cocoa Touch框架中,“根”类时NSObject类.同样, ...
- iOS系列 基础篇 07 Action动作和输出口
iOS系列 基础篇 07 Action动作和输出口 目录: 1. 前言及案例说明 2. 什么是动作? 3. 什么是输出口? 4. 实战 5. 结尾 1. 前言及案例说明 上篇内容我们学习了标签和按钮 ...
- Android开发—智能家居系列】(二):用手机对WIFI模块进行配置
在实际开发中,我开发的这款APP是用来连接温控器,并对温控器进行控制的.有图为证,哈哈. 上一篇文章[Android开发—智能家居系列](一):智能家居原理的文末总结中写到: 手机APP控制智能温控器 ...
随机推荐
- Linux 服务器的性能参数指标总结
关注「开源Linux」,选择"设为星标" 回复「学习」,有我为您特别筛选的学习资料~ 前言 一个基于 Linux 操作系统的服务器运行的同时,也会表征出各种各样参数信息.通常来说运 ...
- c++:-3
上一节学习了C++的函数:c++:-2,本节学习C++的数组.指针和字符串 数组 定义和初始化 定义 例如:int a[10]; 表示a为整型数组,有10个元素:a[0]...a[9] 例如: int ...
- Java学习笔记-基础语法Ⅷ-泛型、Map
泛型 泛型本质上是参数化类型,也就是说所操作的数据类型被指定为一个参数,即将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型,这种参数类型可以用在类.方法和接口中,分别为泛型类.泛型方法 ...
- 使用client-go实现自定义控制器
使用client-go实现自定义控制器 介绍 我们已经知道,Service对集群之外暴露服务的主要方式有两种:NodePort和LoadBalancer,但是这两种方式,都有一定的缺点: NodePo ...
- Web安全学习笔记 SQL注入下
Web安全学习笔记 SQL注入下 繁枝插云欣 --ICML8 SQL注入小技巧 CheatSheet 预编译 参考文章 一点心得 一.SQL注入小技巧 1. 宽字节注入 一般程序员用gbk编码做开发的 ...
- Spring Boot 配置 HikariCP
HikariCP 是一个可靠的.高性能的 JDBC 连接池 本来用的 alibaba/druid,但实际并没有怎么用其内置的监控网页,然后多方调查,决定弃用 druid,替换为 HikariCP Sp ...
- unity---给物体施加普通力和位置力
普通力 让物体沿着某一方向获得一个力,vector3方向 addForceObj.GetComponent<Rigidbody>().AddForce(1000,0,1000); 位置力 ...
- Java实现飞机大战游戏
飞机大战详细文档 文末有源代码,以及本游戏使用的所有素材,将plane2文件复制在src文件下可以直接运行. 实现效果: 结构设计 角色设计 飞行对象类 FlyObject 战机类 我的飞机 MyPl ...
- 如何在 pyqt 中自定义工具提示 ToolTip
前言 Qt 自带的工具提示样式不太好看,就算加了样式表也时不时会失效,同时工具提示没有阴影,看起来就更难受了.所以本篇博客将会介绍自定义工具提示的方法,效果如下图所示: 实现过程 工具提示其实就是一个 ...
- [补漏]shift&算法
题意:regular number 给你一个字符串,要你输出所有(每位都符合要求的)子串,输入时告诉你每位只能填的数集. 思路: bitsetc[x]存每个数字可以存在的字符串位的二进制集合.(如3可 ...