Swift学习笔记 (二) 基础部分(中)

类型安全和类型推断

Swift 是一个类型安全(type safe)的语言,它会在编译你的代码时进⾏类型检查(type checks),并把不匹配的类型标记为错误。

 如果你没有显式指定类型,Swift 会使用类型推断(type inference)来选择合适的类型。

当你在声明常量或者变量的时候赋给它们一个字面量(literal value 或 literal)即可触发类型推断。(字⾯量就是会直接出现在你代码

中的值,⽐如: 42 和 3.14159 。)

例如,如果你给一个新常量赋值 42 并且没有标明类型,Swift 可以推断出常量类型是 Int ,因为你给它赋的初始值 看起来像一个

整数

let meaningOfLife = 42          // meaningOfLife 会被推测为 Int 类型

同理,如果你没有给浮点字⾯量标明类型,Swift 会推断你想要的是 Double :

let pi = 3.14159             // pi 会被推测为 Double 类型

当推断浮点数的类型时,Swift 总是会选择 Double ⽽不是 Float 。

如果表达式中同时出现了整数和浮点数,会被推断为 Double 类型:

let anotherPi = 3 + 0.14159        // anotherPi 会被推测为 Double 类型

 

数值型字⾯面量量

整数字⾯量可以被写作:

一个十进制数,   没有前缀         let decimalInteger = 17

⼀个二进制数,   前缀是 0b       let binaryInteger = 0b10001     // ⼆进制的17

一个八进制数,   前缀是 0o       let octalInteger = 0o21  // ⼋进制的17

一个十六进制数,前缀是 0x       let hexadecimalInteger = 0x11  // ⼗六进制的17

浮点字⾯量可以是十进制(没有前缀)或者是⼗六进制(前缀是 0x )。小数点两边必须有⾄少一个十进制数字(或者是⼗六进制的数

字)。十进制浮点数也可以有一个可选的指数(exponent),通过⼤写或者⼩写的 e 来指定;⼗六进制浮点数必须有一个指数,通过

⼤写或者⼩写的 p 来指定。

如果⼀个⼗进制数的指数为 exp ,那这个数相当于基数和10^exp 的乘积:

1.25e2 表示 1.25 × 10^2,等于 125.0 。

1.25e-2 表示 1.25 × 10^-2,等于 0.0125 。

如果⼀个⼗六进制数的指数为 exp ,那这个数相当于基数和2^exp 的乘积:

0xFp2 表示 15 × 2^2,等于 60.0 。

0xFp-2 表示 15 × 2^-2,等于 3.75 。

下⾯的这些浮点字⾯量都等于十进制的 12.1875 :

let decimalDouble = 12.1875

let exponentDouble = 1.21875e1

let hexadecimalDouble = 0xC.3p0

数值类字⾯量可以包括额外的格式来增强可读性。整数和浮点数都可以添加额外的零并且包含下划线,并不会影响字面量:

let paddedDouble = 000123.456

let oneMillion = 1_000_000

let justOverOneMillion = 1_000_000.000_000_1

 

数值型类型转换

通常来讲,即使代码中的整数常量和变量已知非负,也请使用 Int 类型。总是使用默认的整数类型可以保证你的整数常量和变量

可以直接被复⽤并且可以匹配整数类字⾯量的类型推断。

只有在必要的时候才使⽤其他整数类型,⽐如要处理外部的长度明确的数据或者为了优化性能、内存占用等等。使用显式指定长

度的类型可以及时发现值溢出并且可以暗示正在处理特殊数据。

 

整数转换

不同整数类型的变量和常量可以存储不同范围的数字。 Int8 类型的常量或者变量可以存储的数字范围是 -128 ~ 127 ,⽽ UInt8 

类型的常量或者变量能存储的数字范围是 0 ~ 255 。如果数字超出了了常量或者变量可存储的范围,编译的时候会报错:

let cannotBeNegative: UInt8 = -1             // UInt8 类型不能存储负数,所以会报错

let tooBig: Int8 = Int8.max + 1                  // Int8 类型不能存储超过最大值的数,所以会报错

要将一种数字类型转换成另一种,你要用当前值来初始化一个期望类型的新数字,这个数字的类型就是你的目标类型。在下面的

例子中,常量 twoThousand 是 UInt16 类型,然而常量 one 是 UInt8 类型。它们不能直接相加,因为它们类型不同。所以要调用

UInt16(one) 来创建一个新的 UInt16 数字并用 one 的值来初始化,然后使用这个新数字来计算:

let twoThousand: UInt16 = 2_000

let one: UInt8 = 1

let twoThousandAndOne = twoThousand + UInt16(one)

现在两个数字的类型都是 UInt16 ,可以进行相加。目标常量 twoThousandAndOne 的类型被推断为 UInt16 ,因为它是两个 

UInt16 值的和。

SomeType(ofInitialValue) 是调用 Swift 构造器并传⼊一个初始值的默认方法。在语言内部, UInt16 有一个构造器,可以接受

一个 UInt8 类型的值,所以这个构造器可以用现有的 UInt8 来创建一个新的 UInt16 。注意,你并不能传入任意类型的值,只能传

入 UInt16 内部有对应构造器的值。不过你可以扩展现有的类型来让它可以接收其他类型的值(包括自定义类型)

 

整数和浮点数转换

整数和浮点数的转换必须显式指定类型:

let three = 3

let pointOneFourOneFiveNine = 0.14159

let pi = Double(three) + pointOneFourOneFiveNine

// pi 等于 3.14159,所以被推测为 Double 类型

注意

结合数字类常量和变量不同于结合数字类字⾯量。字⾯量 3 可以直接和字⾯量 0.14159 相加,因为数字字⾯量本身没有明确的类

型。它们的类型只在编译器需要求值的时候被推测。

 

类型别名

类型别名(type aliases)就是给现有类型定义另一个名字。你可以使用 typealias 关键字来定义类型别名。 当你想要给现有类型

起一个更有意义的名字时,类型别名非常有用。假设你正在处理特定长度的外部资源的数据:

typealias AudioSample = UInt16

定义了一个类型别名之后,你可以在任何使用原始名的地方使用别名:

var maxAmplitudeFound = AudioSample.min

// maxAmplitudeFound 现在是 0

本例中, AudioSample 被定义为 UInt16 的一个别名。因为它是别名, AudioSample.min 实际上是UInt16.min ,所以会给 

maxAmplitudeFound 赋一个初值 0 。

 

布尔值

Swift 有一个基本的布尔(Boolean)类型,叫做 Bool 。布尔值指逻辑上的值,因为它们只能是真或者假。Swift 有两个布尔常

量, true 和 false :

let turnipsAreDelicious = false

当你编写条件语句比如 if 语句的时候,布尔值⾮常有用:

if turnipsAreDelicious {

      print("Mmm, tasty turnips!")

} else {

      print("Eww, turnips are horrible.")

}

// 输出“Eww, turnips are horrible.”

如果你在需要使用 Bool 类型的地⽅使用了非布尔值,Swift 的类型安全机制会报错。下⾯的例子会报告一个编译时错误:

let i = 1

if i {

// 这个例子不会通过编译,会报错

}

然而,下⾯的例子是合法的:

let i = 1

if i == 1 {

// 这个例子会编译成功

}

i == 1 的⽐较结果是 Bool 类型,所以第二个例子可以通过类型检查。

和 Swift 中的其他类型安全的例子一样,这个方法可以避免错误并保证这块代码的意图总是清晰的。

 

元组

元组(tuples)把多个值组合成一个复合值。元组内的值可以是任意类型,并不要求是相同类型。

下⾯这个例子中, (404, "Not Found") 是一个描述 HTTP 状态码(HTTP status code)的元组。HTTP 状态码是当你请求⽹页的时

候 web服务器返回的一个特殊值。如果你请求的⽹页不存在就会返回一个 404 Not Found 状态码。

let http404Error = (404, "Not Found")

// http404Error 的类型是 (Int, String),值是 (404, "Not Found")

(404, "Not Found") 元组把一个 Int 值和一个 String 值组合起来表示 HTTP 状态码的两个部分:一个数字和 一个⼈类可读的描述。

这个元组可以被描述为“一个类型为 (Int, String) 的元组”。你可以把任意顺序的类型组合成一个元组,这个元组可以包含所有类

型。只要你想,你可以创建一个类型为 (Int, Int, Int) 或者 (String, Bool) 或者其他任何你想要的组合的元组。

你可以将一个元组的内容分解(decompose)成单独的常量和变量,然后你就可以正常使用它们了:

let (statusCode, statusMessage) = http404Error

print("The status code is \(statusCode)")

// 输出“The status code is 404”

print("The status message is \(statusMessage)")

// 输出“The status message is Not Found”

如果你只需要一部分元组值,分解的时候可以把要忽略的部分用下划线( _ )标记:

let (justTheStatusCode, _) = http404Error

print("The status code is \(justTheStatusCode)")

// 输出“The status code is 404”

此外,你还可以通过下标来访问元组中的单个元素,下标从零开始:

print("The status code is \(http404Error.0)")

// 输出“The status code is 404”

print("The status message is \(http404Error.1)")

// 输出“The status message is Not Found”

作为函数返回值时,元组非常有⽤。一个⽤来获取网页的函数可能会返回一个 (Int, String) 元组来描述是否获取成功。和只能返

回⼀个类型的值比较起来,一个包含两个不同类型值的元组可以让函数的返回信息更有用。

注意

当遇到一些相关值的简单分组时,元组是很有用的。元组不适合用来创建复杂的数据结构。如果你的数据结构比较复杂,不要使

用元组,用类或结构体去建模。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值