Swift 语言入门
开发环境
官方推荐使用xcode进行编码,但是使用xcode的前提是必须拥有一台Mac电脑(或者黑苹果),因为xcode只能运行在苹果的系统上。
但是如果有ipad也可以用ipad上的Swift Playground这款App先做一些学习和尝试,上面也可以运行playground代码和构建app。
Swift的历史和特点
2014年由Apple公司推出,后来开源。来源于C和Objective-C语言,拥有很多其中的特征。
Swift具有如下一些特性:
- 语法简洁。
- 可选类型,意味着有些值可以不存在。类似于Python中的Optional[]。
- 类型推断。只需要通过let和var来声明类型,不需要指定具体的类型,编译器会完成类型的推断工作。
- 类型安全。
- 自动引用计数ARC。
- 元组和多个返回值。
- 泛型。
- 快速在集合上进行迭代。
- 支持方法、扩展和协议的结构体。
- map filter reduce等常用的函数式贬称规模性支持。
- 强大的错误处理机制。
不需要分号结尾,不需要严格的缩进。注释用//和/**/表示。///表示文档注释,会出现在按 Option 键点击查看文档的时候。文档注释中如果使用- Parameter xxx: xxxx
表示解释传入的参数 - Note:
表示其他笔记说明
常量、变量数据类型
常量通过let声明,一旦声明无法更改。
变量通过var声明,声明之后仍然可以对其值进行修改。
尽管var可以替代let,但是声明成常量仍然有一些好处,比如避免修改常量的值让程序更安全,编译器会针对常量进行优化。
变量命名规范:官方推荐采用小驼峰方式对变量进行命名,实际上变量中可以出现各种字符(除了空白字符和数学符号)
常见类型:
- Int 整数
- Double 双精度浮点数
- Bool 布尔,true和false,小写。
- String 字符串
- Array 数组
- Dictionary 字典
- Set 集合
- Sequence 序列
- Error 错误
可以自定义类型,形式略像C的结构体:
struct Person{
let firstName: String
let lastName: String
func sayHello() {
print("hello, my name is \(firstName) \(lastName).")
}
}
let person: Person = Person(firstName:"haha", lastName:"yes")
person.sayHello()
在Swift中,变量和常量在声明的时候类型虽然不需要明确指定,但是已经被编译器推断并确定了。之后,不能像python一样随意改变一个变量(常量)的类型,否则会引发错误,这就是Swift的类型安全。这种类型安全要求很严格,即使是Int和Double之间也必须遵循,不会存在C和C++中的那种隐式类型转换。
表示数字时,可以在数字中间加下换线来方便阅读,例如199_2等同于1992。
尽管编译器会帮忙在声明变量和常量时推断类型,也可以用冒号(:)类型标注,更加方便阅读。var playScore:Double = 19
语句中,会进行隐式类型转换,这说明,变量赋值之前的隐式转换还是存在的,编译器会先匹配手动声明的类型完成转换再赋值。
类型标注通常用在:只声明不初始化,不希望被推断(如Character类型可能被推断为String),声明自定义类型的成员变量。
关于类型,Swift的原则是,必须要标注或者能推断出变量和常量的类型,否则不通过。不能使用没有赋值的变量和常量。对于常量,如果声明的时候没有赋值,则后来只能赋值一次。
另外还可以声明一些其他类型的数字,如UInt8表示0~255之间的8位整数。
运算符
Swift支持赋值(=) 四则运算(+-*/)
对于二元运算符,如果两边类型不同,通常是无法计算的。字面量的整数会被转换为Double运算,而变量不行。对于Int型相除,结果是向下取整的。
var haha = 1 * 1.2 // ok, 结果1.2
var h1 = 1, h2 = 1.2
var haha2 = h1 * h2 // 不行,报错,Int和Double不能相乘
常见的复合赋值运算符(+= -= *= /=)都可以使用。
可以用%来求余数,但是只支持整数取模。
类型转换:所有需要用到类型转换的地方都需要显式指明。例如let pi = Double(x) + y
控制流程
逻辑、比较运算符:== != > <= < && ||! 和C语言一样的。
if语句:
let temperature = 100
if temperature >= 100 {
print("steam")
} else if temperature <= 0 {
print("ice")
} else {
print("water")
}
switch语句(同C):
switch numberOfWheels {
case 1:
print("Unicycle")
case 2:
print("Bicycle")
case 3:
print("Tricycle")
case 4:
print("Quadcycle")
case 5, 6, 7:
print("Too many")
case ...0: // 包含0
print("error")
case 8...12: // 包含8,12
print("Too too many")
case 13...: // 包含13
print("error")
default:
print("error")
}
switch语句中必须有default。范围选择时包含两端。
三元运算符 ? : 也可以用。largest = a > b ? a : b
函数
函数声明和调用:
func hello(name: String) {
print("Hello " + name)
}
hello(name: "Maria")
hello(name: "Vikram")
调用的时候必须要写明传入的参数是哪一个。
也可以像下面一样给参数定义一个外部名称,这样在调用的时候就必须通过外部名称来传入参数。
func hello(anotherName name: String) {
print("Hello " + name)
}
hello(anotherName: "John")
如果想忽略外部参数名,可以将外部参数名指定为_,就可以不用外部参数名传入这个参数。例如:
func hello(_ name: String) {
print("Hello " + name)
}
hello("John")
数组
由于Swift当中没有引用的概念,因此let声明的数组是真的常量数组,数组任何一个元素不允许变化。但是即使用var创建数组,数组元素的类型也不能改变了。
可以使用
for xxx in xxxs
来迭代遍历数组元素,需要注意和Python中只有函数作用域不同,Swift这里变量具有块级作用域,也就是说xxx这个变量只能在循环内使用,越过循环之后不能使用。对比Python这里,for i in range(3)
在外面还是可以使用i变量的。添加元素:
list.append(xx)
返回添加后的数组list.insert(xx, at: 0)
返回添加后的数组list += [1,2,3]
如同python一样使用
删除元素:
list.remove(at: 2)
返回删除的元素list.removeFirst()
返回删除的元素list.removeLast()
返回删除的元素list.removeAll()
无返回值
list.count
count属性得到数组当前大小数组类型可以用类似于
[Bool]
的表达来指示类型使用
0 ... 5
类似的形式表示0到5(包含两端)的范围,可以在for in中如同python的range一样使用。
字符串
- 可以在字符串里用\()来表示此处带入外部变量,形成格式化字符串。例如
"hello, \(name)"
结构体
如果想修改结构体的字段,不仅要结构体中定义的该字段是var而不是let(变量),而且创建结构体实例的时候也要使用var而不是let。双重解锁才能更改结构体字段值。
计算属性:特殊的属性,取值时会根据其他字段或条件当场计算得出。有点类似vue里的计算量。计算属性必须用var声明。计算属性内部写法也是return,有点像简化后的函数。
swift规定一切变量使用前都应该初始化。
在Swift中采用如下形式定义结构体:
struct Foo { let size: Int var haha: String } let newFoo = Foo()
Enum 枚举 和 switch
enum LunchChoice {
case pasta, burger
case soup
}
var choice: LunchChoice
choice = .soup
为什么要将枚举和switch语句相提并论呢?因为swift中如果switch的是一个枚举类型,一定要在switch中包含所有情况:
func cookLunch(_ choice: LunchChoice) -> String {
switch choice{
case .pasta, .burger:
return "no"
case .soup:
return "yes"
}
}
如果不是枚举类型,则可以使用default来规定默认处理方法。
在枚举类型里面,可以用一个计算属性,包含switch self来得到自身其他内容:
enum LunchChoice {
case pasta, burger
case soup
var price: Int {
switch self{
case .pasta, .soup: return 10
case .burger: return 20
}
}
}
enum中也可以定义函数。在swift中,引用自身实例的属性,也可以在前面加一个self.