您的位置:首页 > 移动开发 > Swift

The Swift Programming Language中文版 ----Language Guide(三)

2014-06-09 17:41 393 查看
搬运帖!原帖地址:http://letsswift.com/2014/06/swift-guide-basic/
16.数值类型转换

为代码中所有通用的数值型整型常量和变量使用Int类型,即使它们已知是非负的。这意味着代码中的数值常量和变量能够相互兼容并且能够与自动推导出的类型相互匹配。

只有因为某些原因(性能,内存占用或者其他必须的优化)确实需要使用其他数值类型的时候,才应该使用这些数值类型。这些情况下使用显式指定长度的类型有助于发现值范围溢出,同时应该留下文档。

17.整数转换

可以存储在一个整数常量或变量的范围根据每个数值类型是不同的。一个Int8常量或变量可以存储范围-128到127之间的数,而一个UInt8常量或变量可以存储0到255之间的数字。错误的赋值会让编译器报错:
let cannotBeNegative: UInt8 = -1
// UInt8 cannot store negative numbers, and so this will report an error
let tooBig: Int8 = Int8.max + 1
// Int8 cannot store a number larger thanits maximum value,
// and so this will also report an error


因为每个数字类型可以存储不同范围的值,你必须在基础数值类型上逐步做转换。这种可以防止隐藏的转换错误,并帮助明确你的代码中类型转换的意图。

要转换一个特定的数字类型到另一个,你需要定义一个所需类型的新变量,并用当前值初始化它。在下面的例子中,常量twoThousand是UInt16类型的,而常量one是UINT8类型的。它们不能被直接相加的,因为类型不同。相反的,该​​示例调用UInt16(one)来创建一个用变量one的值初始化的UInt16类型的新变量,并且使用这个值来代替原来的值参与运算:
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初始化能接受的类型。如何扩展现有类型,规定接受新的类型(包括你自己的类型定义)。
18.整数和浮点数转换

整数和浮点类型之间的转化必须显式声明:
let three = 3
let pointOneFourOneFiveNine= 0.14159
let pi = Double(three) +pointOneFourOneFiveNine
// pi equals 3.14159, and is inferred to beof typde Double


这里,常量three的值被用来创建Double类型的新变量,从而使表达式两侧是相同的类型。如果没有这个转换,加法操作不会被允许。反之亦然,一个整数类型可以用double或float值进行初始化:
let integerPi= Int(pi)
// integerPi equals 3, and is inferred tobe of type Int


当使用这种方式初始化一个新的整数值的时候,浮点值总是被截断。这意味着,4.75变为4,和-3.9变为-3。

注:数值类型常量/变量的类型转换规则和数字类型常值的转换规则不同。常值3可以直接与常值0.14159相加,因为常值没有一个明确的类型。他们的类型是被编译器推导出来的。

19.类型别名

类型别名为现有类型定义的可替代名称。你可以使用typealias关键字定义类型别名。类型别名可以帮助你使用更符合上下文语境的名字来指代一个已存在的类型,比如处理一个外来的有指定长度的类型的时候:
typealias AudioSample = UInt16


一旦你定义了一个类型别名,你可以在任何可能使用原来的名称地方使用别名:
var maxAmplitudeFound= AudioSample.min
// maxAmplitudeFound is now 0


这里,AudioSample被定义为一个UInt16的别名。因为它是一个别名,调用AudioSample.min实际上是调用UInt16.min,从而给maxAmplitudeFound变量赋初始值0。
20.布尔类型

Swift中的布尔类型使用Bool定义,也被称为Logical(逻辑)类型,可选值是true和false:
let orangesAreOrange = true
let turnipsAreDelicious = false


这里 orangesAreOrange和turnipsAreDelicious的类型被推导为Bool 因为他们被初始化被Bool类型的常值。跟Int和Double类型一样,在定义布尔类型的时候不需要显式的给出数据类型,只需要直接赋值为true或false即可 。当使用确定类型的常值初始化一个常量/变量的时候,类型推导使Swift代码更精确和可读。 布尔类型在条件语句中特别适用,比如在if语句中
if turnipsAreDelicious {
println("Mmm, tasty turnips!")
} else {
println("Eww, turnips are horrible.")
}
// prints "Eww, turnips are horrible."


像if语句这样的条件语句,我们会在之后的章节ControlFlow有详细介绍。
Swift的类型安全策略会防止其他非布尔类型转换为布尔类型使用,比如
let i = 1
if i {
// this example will not compile, and will report an error
}


就会报错,但这在其他编程语言中是可行的。但是如下的定义是正确的:
let i = 1
if i == 1 {
// this example will compile successfully
}


i == 1的结果就是一个布尔类型,所以可以通过类型检查。像i==1这种比较将会在章节[Basic Operators]中讨论。上面的例子也是一个Swift类型安全的例子。类型安全避免了偶然的类型错误,保证了代码的意图是明确的。

21.元组类型

元组类型可以将一些不同的数据类型组装成一个元素,这些数据类型可以是任意类型,并且不需要是同样的类型。

在下面的例子中,(404, “Not Found”) 是一个HTTP状态码。HTTP状态码是请求网页的时候返回的一种特定的状态编码。404错误的具体含义是页面未找到。

let http404Error = (404, “Not Found”) // http404Error is of type (Int, String), and equals (404, “Not Found”)

这个元组由一个Int和一个字符串String组成,这样的组合即包含了数字,也包含了便于人们认知的字符串描述。这个元组可以描述为类型(Int,String)的元组。

编程人员可以随意地创建自己需要的元组类型,比如 (Int, Int, Int), 或者(String, Bool)等。同时组成元组的类型数量也是不限的。 可以通过如下方式分别访问一个元组的值:
let (statusCode, statusMessage) = http404Error
println("The status code is \(statusCode)")
// prints "The status code is 404"
println("The status message is \(statusMessage)")
// prints "The status message is Not Found"


如果仅需要元组中的个别值,可以使用(_)来忽略不需要的值
let (justTheStatusCode, _) = http404Error
println("The status code is \(justTheStatusCode)")
// prints "The status code is 404"


另外,也可以使用元素序号来选择元组中的值,注意序号是从0开始的
println("The status code is \(http404Error.0)")
// prints "The status code is 404"
println("The status message is \(http404Error.1)")
// prints "The status message is Not Found"


在创建一个元组的时候,也可以直接指定每个元素的名称,然后直接使用元组名.元素名访问,如:
let http200Status = (statusCode: 200, description: "OK")
println("The status code is \(http200Status.statusCode)")
// prints "The status code is 200"
println("The status message is \(http200Status.description)")
// prints "The status message is OK"


元组类型在作为函数返回值的时候特别适用,可以为函数返回更多的用户需要的信息。比如一个请求web页面的函数可以返回(Int,String)类型的元组来表征页面获取的成功或者失败。返回两个不同类型组成的元组可以比只返回一个类型的一个值提供更多的返回信息。详见

22.可选类型

在一个值可能不存在的时候,可以使用可选类型。这种类型的定义是:要么存在这个值,且等于x,要么在这个值 不存在。

注:这种类型在C和Objective-C中是不存在的,但是Objective-C中有一个相似的类型,叫nil,但是仅仅对对象有用。对其他的情况,Object-C方法返回一个特殊值(比如NSNotFound)来表明这个值不存在。这种方式假设方法调用者知道这个特殊值的存在和含义。Swift的可选类型帮助你定义任意的值不存在的情况。

下面给出一个例子,在Swift中String类型有一个叫toInt的方法,能够将一个字符串转换为一个Int类型。但是需要注意的是,不是所有的字符串都可以转换为整数。比如字符串”123″可以转换为123,但是”hello, world”就不能被转换。
let possibleNumber = "123"
let convertedNumber = possibleNumber.toInt()
// convertedNumber is inferred to be of type "Int?", or "optional Int"


由于toInt方法可能会失败,因此它会返回一个可选的Int类型,而不同于Int类型。一个可选的Int类型被记为Int?,不是Int。问号表明它的值是可选的,可能返回的是一个Int,或者返回的值不存在。

23.if语句和强制解包

编程人员可以使用if语句来检测一个可选类型是否包含一个特定的值,如果一个可选类型确实包含一个值,在if语句中它将返回true,否则返回false。如果你已经检测确认该值存在,那么可以使用或者输出它,在输出的时候只需要在名称后面加上感叹号(!)即可,意思是告诉编译器:我已经检测好这个值了,可以使用它了。如:
if convertedNumber {
println("\(possibleNumber) has an integer value of \(convertedNumber!)")
} else {
println("\(possibleNumber) could not be converted to an integer")
}
// prints "123 has an integer value of 123"


24.选择绑定

选择绑定帮助确定一个可选值是不是包含了一个值,如果包含,把该值转化成一个临时常量或者变量。选择绑定可以用在if或while语句中,用来在可选类型外部检查是否有值并提取可能的值。

方法如下:
if let constantName = someOptional {
statements
}


那么上一个例子也可以改写为:
if let actualNumber = possibleNumber.toInt() {
println("\(possibleNumber) has an integer value of \(actualNumber)")
} else {
println("\(possibleNumber) could not be converted to an integer")
}
// prints "123 has an integer value of 123"


上述代码理解起来不难:如果possibleNumber.toInt 返回的这个可选Int类型包含一个值,那么定义一个常量actualNumber来等于这个值,并在 后续代码中直接使用。

如果转换是成功的,那么actualNumber常量在if的第一个分支可用,并且被初始化为可选类型包含的值,同时也不需要使用!前缀。这个例子里,actualNumber只是简单的被用来打印结果。

常量和变量都可以用来做可选绑定。如果你想要在if第一个分支修改actualNumber的值,可以写成if var actualNumber, actualNumber就成为一个变量从而可以被修改。


25.nil

可以给可选类型指定一个特殊的值nil:
var serverResponseCode: Int? = 404
// serverResponseCode contains an actual Int value of 404
serverResponseCode = nil
// serverResponseCode now contains no value


如果你定义了一个可选类型并且没有给予初始值的时候,会默认设置为nil

var surveyAnswer: String? // surveyAnswer is automatically set to nil

注: Swift 的nil不同于Object-C中的nil. Object-C中,nil是一个指针指向不存在的对象。Swift中,nil不是指针而是一个特定类型的空值。任何类型的可选变量都可以被设为nil,不光是指针。


26.隐式解包可选类型

在上面的例子中,可选类型表示一个常量/变量可以没有值。可选类型可以被if语句检测是否有值,并且可以被可选绑定解包。

但是在一些情况下,可选类型是一直有效的,那么可以通过定义来隐式地去掉类型检查,强制使用可选类型。这些可选类型被成为隐式解包的可选类型。你可以直接在类型后面加! 而不是?来指定。

隐式解包的可选类型主要用在一个变量/常量在定义瞬间完成之后值一定会存在的情况。这主要用在类的初始化过程中。

隐式解包的可选类型本质是可选类型,但是可以被当成一般类型来使用,不需要每次验证值是否存在。如下的例子展示了可选类型和解包可选类型之间的区别。
let possibleString: String? = "An optional string."
println(possibleString!) // requires an exclamation mark to access its value
// prints "An optional string."

let assumedString: String! = "An implicitly unwrapped optional string."
println(assumedString) // no exclamation mark is needed to access its value
// prints "An implicitly unwrapped optional string."


你可以把隐式解包可选类型当成对每次使用的时候自动解包的可选类型。即不是每次使用的时候在变量/常量后面加!而是直接在定义的时候加。

注:如果一个隐式解包的可选类型不包含一个实际值,那么对它的访问会抛出一个运行时错误。在变量/常量名后面加!的情况也是一样的。

你依然可以把解包可选类型当成正常的可选类型来探测是否有值。
if assumedString {
println(assumedString)
}
// prints "An implicitly unwrapped optional string."


或者通过选择绑定检查
if let definiteString = assumedString {
println(definiteString)
}
// prints "An implicitly unwrapped optional string."


注:如果一个可选类型存在没有值的可能的话,不应该使用解包可选类型。这种情况下,一定要使用正常的可选类型。


27.断言

可选类型让编程人员可以在运行期检测一个值是否存在,然后使用代码来处理不存在的情况。但是有些情况下,如果一个值 不存在或者值不满足条件会直接影响代码的执行,这个时候就需要使用断言。这种情况下,断言结束程序的执行从而提供调试的依据。


28.使用断言调试

断言是一种实时检测条件是否为true的方法,也就是说,断言假定条件为true。断言保证了后续代码的执行依赖于条件的成立。如果条件满足,那么代码继续执行,如果这个条件为false,那么代码将会中断执行。

在Xcode中,在调试的时候如果中断,可以通过查看调试语句来查看断言失败时的程序状态。断言也能提供适合的debug信息。 使用全局函数assert来使用断言调试,assert函数接受一个布尔表达式和一个断言失败时显示的消息,如:
let age = -3
assert(age >= 0, "A person's age cannot be less than zero")
// this causes the assertion to trigger, because age is not >= 0


当前一个条件返回false的时候,后面的错误日志将会输出。

在这个例子中,只有当age >= 0的时候,条件被判定为true,但是age = -3,所以条件判定为false,输出错误日志 “A person’s age cannot be less than zero”。

当然错误日志也可以省略,但是这样不利于调试,如
assert(age >= 0)


29.使用断言的时机

当需要检测一个条件可能是false,但是代码运行必须返回true的时候使用。下面给出了一些常用场景,可能会用到断言检测:

传递一个整数类型下标的时候,比如作为数组的Index,这个值可能太小或者太大,从而造成数组越界;

传递给函数的参数,但是一个无效的参数将不能在该函数中执行

一个可选类型现在是nil,但是在接下来的代码中,需要是非nil的值才能够继续运行。

注:断言会导致程序运行的中止,所以如果异常是预期可能发生的,那么断言是不合适的。这种情况下,异常是更合适的。断言保证错误在开发过程中会被发现,发布的应用里最好不要使用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: