Swift 初见
学习swift的记录
控制台输出
print("hello world")
可以无分号!!!!!!!
变量声明
let 常量声明 如果在常量声明后再次修改他会报错
var 变量声明
一个常量的值,在编译的时候,并不需要有明确的值,但是你只能为它赋值一次。这说明你可以用一个常量来命名一个值,一次赋值就可在多个地方使用
let a = 3
var b = 5
print(a, b)
如果初始值没有提供足够的信息(或者没有初始值),那你需要在变量后面声明类型,用冒号分割。
值永远不会被隐式转换为其他类型。如果你需要把一个值转换成其他类型,请显式转换。
有一种更简单的把值转换成字符串的方法:把值写到括号中,并且在括号之前写一个反斜杠(\)
使用三个双引号(“”")来包含多行字符串内容。每行行首的缩进会被去除,只要和结尾引号的缩进相匹配。
使用方括号 [] 来创建数组和字典,并使用下标或者键(key)来访问元素。最后一个元素后面允许有个逗号
使用初始化语法来创建一个空数组或者空字典。
如果类型信息可以被推断出来,你可以用 [] 和 [:] 来创建空数组和空字典——比如,在给变量赋新值或者给函数传参数的时候
选择和循环
使用 if 和 switch 来进行条件操作,使用 for-in、while 和 repeat-while 来进行循环。包裹条件和循环变量的括号可以省略,但是语句体的大括号是必须的
可以一起使用 if 和 let 一起来处理值缺失的情况。这些值可由可选值来代表。一个可选的值是一个具体的值或者是 nil 以表示值缺失。在类型后面加一个问号(?)来标记这个变量的值是可选的。
另一种处理可选值的方法是通过使用 ?? 操作符来提供一个默认值。如果可选值缺失的话,可以使用默认值来代替。
switch 支持任意类型的数据以及各种比较操作——不仅仅是整数以及测试相等。
使用 while 来重复运行一段代码直到条件改变。循环条件也可以在结尾,保证能至少循环一次。
可以在循环中使用 …< 来表示下标范围。
使用 …< 创建的范围不包含上界,如果想包含的话需要使用 …。
函数和闭包
默认情况下,函数使用它们的参数名称作为它们参数的标签,在参数名称前可以自定义参数标签,或者使用 _ 表示不使用参数标签
使用元组来生成复合值,比如让一个函数返回多个值。该元组的元素可以用名称或数字来获取
函数可以嵌套。被嵌套的函数可以访问外侧函数的变量,你可以使用嵌套函数来重构一个太长或者太复杂的函数。
函数是第一等类型,这意味着函数可以作为另一个函数的返回值
函数也可以当做参数传入另一个函数
函数实际上是一种特殊的闭包:它是一段能之后被调取的代码。闭包中的代码能访问闭包作用域中的变量和函数,即使闭包是在一个不同的作用域被执行的——你已经在嵌套函数的例子中看过了。你可以使用 {} 来创建一个匿名闭包。使用 in 将参数和返回值类型的声明与闭包函数体进行分离
对象和类
使用 class 和类名来创建一个类。类中属性的声明和常量、变量声明一样,唯一的区别就是它们的上下文是类。同样,方法和函数声明也一样
class Shape {var numberOfSize = 0func simpleDescription() -> String {return "A shape with \(numberOfSize) sides."}}
要创建一个类的实例,在类名后面加上括号。使用点语法来访问实例的属性和方法
class NamedShape {var numberOfSize: Int = 0var name: Stringinit(name: String){self.name = name}func simpleDescription() -> String {return "A shape with \(numberOfSize) sides."}}
注意 self 被用来区别实例变量 name 和构造器的参数 name。当你创建实例的时候,像传入函数参数一样给类传入构造器的参数。每个属性都需要赋值——无论是通过声明(就像 numberOfSides)还是通过构造器(就像 name)。
如果你需要在对象释放之前进行一些清理工作,使用 deinit 创建一个析构函数。
子类的定义方法是在它们的类名后面加上父类的名字,用冒号分割。创建类的时候并不需要一个标准的根类,所以你可以根据需要添加或者忽略父类。
子类如果要重写父类的方法的话,需要用 override 标记——如果没有添加 override 就重写父类方法的话编译器会报错。编译器同样会检测 override 标记的方法是否确实在父类中。
枚举和结构体
使用 enum 来创建一个枚举。就像类和其他所有命名类型一样,枚举可以包含方法
enum Rank: Int {case ace = 1case two, three, four, five, six, sever, eight, nine, tencase jack, queen, kingfunc simpleDescription() -> String {switch self {case .ace:return "ace"case .jack:return "jack"case .queen:return "queen"case .king:return "king"default:return String(self.rawValue)}}
默认情况下,Swift 按照从 0 开始每次加 1 的方式为原始值进行赋值,不过你可以通过显式赋值进行改变。在上面的例子中,Ace 被显式赋值为 1,并且剩下的原始值会按照顺序赋值。你也可以使用字符串或者浮点数作为枚举的原始值。使用 rawValue 属性来访问一个枚举成员的原始值。
使用 init?(rawValue:) 初始化构造器来从原始值创建一个枚举实例。如果存在与原始值相应的枚举成员就返回该枚举成员,否则就返回 nil
枚举值是实际值,并不是原始值的另一种表达方法。实际上,如果没有比较有意义的原始值,你就不需要提供原始值
enum Suit {case spades, hearts, diamonds, clubsfunc simpleDescriptions() -> String {switch self {case .spades:return "spades"case .hearts:return "hearts"case .diamonds:return "diamonds"case .clubs:return "clubs"}}}let hearts = Suit.heartslet heartsDescription = hearts.simpleDescriptions()
并发性
使用 async 标记异步运行的函数
func fetchUserID(from server: String) async -> Int {if server == "primary" {return 97}return 501}
还可以通过在函数名前添加 await 来标记对异步函数的调用
func fetchUsername(from server: String) async -> String {let userID = await fetchUsername(from: server)if userID = 501 {return "john Appleseed"}return "Guest"}
使用 async let 来调用异步函数,并让其与其它异步函数并行运行。 使用 await 以使用该异步函数返回的值
func connectUser(to server: String) async {async let userID = fetchUserID(from: server)async let username = fetchUsername(from: server)let greeting = await "Hello \(username), user ID \(userID)"print(greeting)
}
使用 Task 从同步代码中调用异步函数且不等待它们返回结果
Task {await connectUser(to: "primary")
}
协议和扩展
使用 protocol 来声明一个协议
protocol ExampleProtocol {var simpleDescription: String{get}mutating func adjust()}
类、枚举和结构体都可以遵循协议
class SimpleClass: ExampleProtocol {var simpleDescription: String = "A very simple class."var anotherProperty: Int = 69105func adjust() {simpleDescription += " Now 100% adjusted."}
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescriptionstruct SimpleStructure: ExampleProtocol {var simpleDescription: String = "A simple structure"mutating func adjust() {simpleDescription += " (adjusted)"}
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription
错误处理
使用采用 Error 协议的类型来表示错误
enum PrinterError: Error {case outOfPapercase noTonercase onFire
}
使用 throw 来抛出一个错误和使用 throws 来表示一个可以抛出错误的函数。如果在函数中抛出一个错误,这个函数会立刻返回并且调用该函数的代码会进行错误处理
func send(job: Int, toPrinter printerName: String) throws -> String {if printerName == "Never Has Toner" {throw PrinterError.noToner}return "Job sent"
}
泛型
在尖括号里写一个名字来创建一个泛型函数或者类型