The Swift Programming Language 5.2-1 for Basic

203 阅读7分钟

常量与变量

常量是赋值之后就不需要更改的,也不允许更改。变量是以后可以随便更改的。

如何声明

/* 会根据赋予的初值自动判断数据类型 */
let maximumNumberOfLoginAttempts = 10 // 常量声明
var currentLoginAttempt = 0 // 变量声明

var x = 0.0, y = 0.0, z = 0.0 // 一次性赋多个值的方法

类型标注

有初始值的时候就不用标明类型,若没有初试值的时候就需要标明类型

var welcomeMessage: String // 记住是紧接着一个冒号再接一个空格
var red, green, blue: Double // 一次性声明多个变量

常量与变量的命名规则

  • 名字里不能包含的字符有
    1. 空白字符
    2. 数学符号
    3. 箭头
    4. private-use Unicode scalar values(私有Unicode标量值)
    5. line- and box-drawing characters.
  • 名字不能以数字开头,但其它地方可以有数字。
  • 无论是常量还是变量,一旦规定了类型,以后就不能再更改。
  • 如果你要使用Swift关键字命名,需要用反引号`包裹,但不建议使用关键字。

打印常量与变量

使用的函数是print(_:separator:terminator:),其中的参数separatorterminator有默认值,不需要的话可以忽略它们,它们的详细用法以后再补

var friendlyWelcome = "Bonjour!"
print(friendlyWelcome) // Bonjour会显示在console上

print("The current value of friendlyWelcome is \(friendlyWelcome)") // 常量或变量插入字符串显示的方法。

注释

  • 单行注释// single line comment
  • 多行注释/* multiline comments */,多行注释是可以嵌套使用的(与C不一样的地方)。

分号的用法

Swift是不需要分号;来表示结束的。

但如果你需要将多行语句写到一行上面,那么就需要分号;来表示分割。 let cat = "🐱"; print(cat)


整数

整型数的命名规律:

  • UInt8:表示8为无符号整型数。
  • Int32:表示32为有符号整型数。

整数范围

使用minmax属性来获取最小值和最大值,记住使用属性(properties)是不需要加圆括号的。

let minValue = UInt8.min // minValue = 0
let maxValue = UInt8.max // maxValue = 255

Int和UInt

它们的范围会根据你的机器硬件而调整。


浮点数

  • float有6位小数点精度。
  • Double有15位小数点精度。
  • 若无特别情况,推荐使用Double

类型安全和类型推断

  • 简单来说,Swift是类型安全的语言,它会自动检测出类型不匹配的错误(与C不一样,在没有你明确说明的情况下,不会自动发生强制类型转换,Int转换成Double也会被认为是error)。
  • Swift也可以根据初始值自动判定类型,不用你明确说明。
  • 浮点数会被判定成Double

数字字面值

  • 不同前缀表示不同的进制
    1. 十进制:无前缀
    2. 二进制:0b
    3. 八进制:0o
    4. 十六进制:0x
  • 科学计算法
    1. 十进制的指数用e(大小写都可以),表示10^{exp}1.25e-2 = 0.0125
    2. 十六进制的浮点数的指数用p(大小写都可以),表示2^{exp}0xFp2 =60.0
    let decimalDouble = 12.1875
    let exponentDouble = 1.21875e1
    let hexadecimalDouble = 0xC.3p0
    // 上面都是十进制值12.1875的表示法
    
  • 方便阅读
    1. 包含多余的0
    2. 包含下划线_
    let paddedDouble = 000123.456
    let oneMillion = 1_000_000
    let justOverOneMillion = 1_000_000.000_000_1
    // 上面的写法都是合法的
    

数字类型转换

如上面所说的,类型的转换必须明确说明,否则会产生错误。

// 下面的语句是错误的
let cannotBeNegative: UInt8 = -1
let tooBig: Int8 = Int8.max + 1

// 两个不同类型的整数相加,必须明确说明转换。
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)

// 整数与浮点数相加,也必须明确说明转换。
let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine

类型别名

使用关键字typealias可以给类型起别名

typealias AudioSample = UInt16
var maxAmplitudeFound = AudioSample.min
// maxAmplitudeFound is now 0

布尔值

truefalse

另外,1不能代表true0不能代表false,这也说明了类型安全。

// 下面语句是错误的
let i = 1
if i {
    code
}

// 下面是正确的
let i = 1
if i == 1 {
    code
}

Tuples

Tuples可以将多个(不限于2个)不同类型的值组合在一起。作为函数返回值很有用。

下面是它的一些用法

let http404Error = (404, "Not Found")

// 直接通过名字索引
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
print("The status message is \(statusMessage)")

// 可以忽视你不想要的元素
let(justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")

// 也可以通过下标索引
print("The status code is \(http404Error.0)")
print("The status message is \(http404Error.1)")

// 或者直接给元素命名
let http200Status = (statusCode: 200, description: "OK")
print("The status code is \(http200Status.statusCode)")
print("The status message is \(http200Status.description)")

Optionals

先看一个例子,Swift可以将String直接转换成Int的,如"123"可以成功转换,但"Hello"是不可以转换成数字的。

let possibleNumber = "123"
let convertedNumber = Int(possibleNumber) 
/*  convertedNumber的类型不是Int,而是Int?,也就是optional Int。
    因为它有可能转换不成功,除了数字可以转换成功,其它的类型都被转换成nil
    所以这时候的optionals就很有用
 */

nil可以使用在任何类型上面,但必须是声明成optionals的类型。

nil的意思是不代表任何值,但它不是空指针。

var surveyAnswer: String?
// 若没有赋初值,Swift会自动将它设置成nil,而不是空字符串

使用!解包optionals去使用该值

if convertedNumber != nil {
    print("convertedNumber has an integer value of \(convertedNumber!).")
}

总之,nil!都只能使用在被声明成optional类型的值上使用,而且解包一个值必须先确定它不是nil

Optional Binding

你在《iOS Apprentice》经常见到的。

/* 下面的let也可以是var */
if let constantName = someOptional { // 如果someOptional不是nil就进行赋值,选择性解包。
    statements
}

// 下面的逗号就相当于&,全部条件成立,if里面的语句才会被执行。
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
    print("\(firstNumber) < \(secondNumber) < 100")
}

Implicitly Unwrapped Optionals

还有一种东西叫模糊解包,主要是用在class initialization的过程中。就是说它保证是有初始值的,所以以后在获取它的值的时候就不需要加叹号!了。你直接看代码感受一下。

/* normal optionals */
let possibleString: String? = "An optional string."
let forcedString: Sting = possibleString! // 需要叹号解包

/* Implicitly Unwrapped Optionals */
let assumedString: String! = "An implicitly unwrapped optional string." // 注意声明类型的时候有叹号!
let implicitsString: String = assumedString // 不需要叹号解包,直接使用即可

注意:

  • 若一个Implicitly Unwrapped Optionalsnil的时候,你去获取它,就会产生一个运行时错误(runtime error)
  • 你也可以把Implicitly Unwrapped Optionals当作正常的optionals使用。
    /* 可以判断是否是nil,也可以使用叹号解包 */
    if assumedString != nil {
        print(assumedString!)
    }
    
    /* 也可以进行optionals binding */
    if let definiteString = assumedString {
        print(definiteString)
    }
    

Error Handling

func makeASandwich() throws {
    // ...
}

do {
    try makeASandwich()
    eatASandwich()
} catch SandwichError.outOfCleanDishes {
    washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
    buyGroceroes(ingredients)
}

do里面try调用了一个可以抛出error的函数makeASandwich(),如果makeASandwich()没有错误则执行eatASandwich(),如果抛出了一个错误,catch根据不同的错误会执行不同的error处理函数。


Assertions and Preconditions

断言和先决条件,与error handling不同的是,不满足断言和先决条件的时候,程序是会直接终止运行的,也就是说程序没有改正错误的机会。

断言和先决条件不同的地方是,断言只在debug阶段其作用,先决条件在debug和production都起作用。

所以你可以在开发阶段尽情的使用断言来辅助你方便地调试程序。

Debugging with Assertions

使用Swift标准库函数assert(_:_:file:line)来使用断言。执行前两条代码:

let age = -3
assert(age >= 0, "A person's age can't be less than zero.") // 如果给到函数的条件是false,则终止进程并打印信息

/* 也可以不要说明信息*/
assert(age >= 0)

会终止进程并产生如下错误。

断言使用例子


下面是不需要检查condition的用法,使用函数assertionFailure(_:file:line:)

if age > 10 {
    print("You can ride the roller-coaster or the ferris wheel.")
} else if age >= 0 {
    print("You can ride the ferris wheel.")
} else {
    assertionFailure("A person's age can't be less than zero.")
}

Enforcing Preconditions

在先决条件中,与Assertions的两个函数对应的是precondition(_:_:file:line:)preconditionFailure(_:file:line:)

因为编译器存在uncheck mode的这样一个模式,开启了这个模式之后,先决条件会失效,即precondition()永远被判定为true。所以存在一个叫fatalError(_:file:line:)的函数,不管是什么编译模式,它都能起作用去终止进程。