make gitbook
This commit is contained in:
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="1.1" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="1.1" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="1.2" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="1.2" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
@ -606,8 +606,9 @@
|
||||
<li><a href="#generics">泛型(Generics)</a></li>
|
||||
</ul>
|
||||
<p>通常来说,编程语言教程中的第一个程序应该在屏幕上打印“Hello, world”。在 Swift 中,可以用一行代码实现:</p>
|
||||
<pre><code>println("Hello, world")
|
||||
</code></pre><p>如果你写过 C 或者 Objective-C 代码,那你应该很熟悉这种形式——在 Swift 中,这行代码就是一个完整的程序。你不需要为了输入输出或者字符串处理导入一个单独的库。全局作用域中的代码会被自动当做程序的入口点,所以你也不需要<code>main</code>函数。你同样不需要在每个语句结尾写上分号。</p>
|
||||
<pre><code class="lang-swift"> println("Hello, world")
|
||||
</code></pre>
|
||||
<p>如果你写过 C 或者 Objective-C 代码,那你应该很熟悉这种形式——在 Swift 中,这行代码就是一个完整的程序。你不需要为了输入输出或者字符串处理导入一个单独的库。全局作用域中的代码会被自动当做程序的入口点,所以你也不需要<code>main</code>函数。你同样不需要在每个语句结尾写上分号。</p>
|
||||
<p>这个教程会通过一系列编程例子来让你对 Swift 有初步了解,如果你有什么不理解的地方也不用担心——任何本章介绍的内容都会在后面的章节中详细讲解。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
@ -616,301 +617,328 @@
|
||||
<p><a name="simple_values"></a></p>
|
||||
<h2 id="-">简单值</h2>
|
||||
<p>使用<code>let</code>来声明常量,使用<code>var</code>来声明变量。一个常量的值在编译时并不需要获取,但是你只能为它赋值一次。也就是说你可以用常量来表示这样一个值:你只需要决定一次,但是需要使用很多次。</p>
|
||||
<pre><code>var myVariable = 42
|
||||
myVariable = 50
|
||||
let myConstant = 42
|
||||
</code></pre><p>常量或者变量的类型必须和你赋给它们的值一样。然而,声明时类型是可选的,声明的同时赋值的话,编译器会自动推断类型。在上面的例子中,编译器推断出<code>myVariable</code>是一个整数(integer)因为它的初始值是整数。</p>
|
||||
<pre><code class="lang-swift"> var myVariable = 42
|
||||
myVariable = 50
|
||||
let myConstant = 42
|
||||
</code></pre>
|
||||
<p>常量或者变量的类型必须和你赋给它们的值一样。然而,声明时类型是可选的,声明的同时赋值的话,编译器会自动推断类型。在上面的例子中,编译器推断出<code>myVariable</code>是一个整数(integer)因为它的初始值是整数。</p>
|
||||
<p>如果初始值没有提供足够的信息(或者没有初始值),那你需要在变量后面声明类型,用冒号分割。</p>
|
||||
<pre><code>let implicitInteger = 70
|
||||
let implicitDouble = 70.0
|
||||
let explicitDouble: Double = 70
|
||||
</code></pre><blockquote>
|
||||
<pre><code class="lang-swift"> let implicitInteger = 70
|
||||
let implicitDouble = 70.0
|
||||
let explicitDouble: Double = 70
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>练习:</p>
|
||||
<p>创建一个常量,显式指定类型为<code>Float</code>并指定初始值为4。</p>
|
||||
</blockquote>
|
||||
<p>值永远不会被隐式转换为其他类型。如果你需要把一个值转换成其他类型,请显式转换。</p>
|
||||
<pre><code>let label = "The width is"
|
||||
let width = 94
|
||||
let widthLabel = label + String(width)
|
||||
</code></pre><blockquote>
|
||||
<pre><code class="lang-swift"> let label = "The width is"
|
||||
let width = 94
|
||||
let widthLabel = label + String(width)
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>练习:</p>
|
||||
<p>删除最后一行中的<code>String</code>,错误提示是什么?</p>
|
||||
</blockquote>
|
||||
<p>有一种更简单的把值转换成字符串的方法:把值写到括号中,并且在括号之前写一个反斜杠。例如:</p>
|
||||
<pre><code>let apples = 3
|
||||
let oranges = 5
|
||||
let appleSummary = "I have \(apples) apples."
|
||||
let fruitSummary = "I have \(apples + oranges) pieces of fruit."
|
||||
</code></pre><blockquote>
|
||||
<pre><code class="lang-swift"> let apples = 3
|
||||
let oranges = 5
|
||||
let appleSummary = "I have \(apples) apples."
|
||||
let fruitSummary = "I have \(apples + oranges) pieces of fruit."
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>练习:</p>
|
||||
<p>使用<code>\()</code>来把一个浮点计算转换成字符串,并加上某人的名字,和他打个招呼。</p>
|
||||
</blockquote>
|
||||
<p>使用方括号<code>[]</code>来创建数组和字典,并使用下标或者键(key)来访问元素。</p>
|
||||
<pre><code>var shoppingList = ["catfish", "water", "tulips", "blue paint"]
|
||||
shoppingList[1] = "bottle of water"
|
||||
|
||||
var occupations = [
|
||||
"Malcolm": "Captain",
|
||||
"Kaylee": "Mechanic",
|
||||
]
|
||||
occupations["Jayne"] = "Public Relations"
|
||||
</code></pre><p>要创建一个空数组或者字典,使用初始化语法。</p>
|
||||
<pre><code>let emptyArray = String[]()
|
||||
let emptyDictionary = Dictionary<String, Float>()
|
||||
</code></pre><p>如果类型信息可以被推断出来,你可以用<code>[]</code>和<code>[:]</code>来创建空数组和空字典——就像你声明变量或者给函数传参数的时候一样。</p>
|
||||
<pre><code>shoppingList = [] // 去逛街并买点东西
|
||||
</code></pre><p><a name="control_flow"></a></p>
|
||||
<pre><code class="lang-swift"> var shoppingList = ["catfish", "water", "tulips", "blue paint"]
|
||||
shoppingList[1] = "bottle of water"
|
||||
</code></pre>
|
||||
<pre><code class="lang-swift"> var occupations = [
|
||||
"Malcolm": "Captain",
|
||||
"Kaylee": "Mechanic",
|
||||
]
|
||||
occupations["Jayne"] = "Public Relations"
|
||||
</code></pre>
|
||||
<p>要创建一个空数组或者字典,使用初始化语法。</p>
|
||||
<pre><code class="lang-swift"> let emptyArray = String[]()
|
||||
let emptyDictionary = Dictionary<String, Float>()
|
||||
</code></pre>
|
||||
<p>如果类型信息可以被推断出来,你可以用<code>[]</code>和<code>[:]</code>来创建空数组和空字典——就像你声明变量或者给函数传参数的时候一样。</p>
|
||||
<pre><code class="lang-swift"> shoppingList = [] // 去逛街并买点东西
|
||||
</code></pre>
|
||||
<p><a name="control_flow"></a></p>
|
||||
<h2 id="-">控制流</h2>
|
||||
<p>使用<code>if</code>和<code>switch</code>来进行条件操作,使用<code>for-in</code>、<code>for</code>、<code>while</code>和<code>do-while</code>来进行循环。包裹条件和循环变量括号可以省略,但是语句体的大括号是必须的。</p>
|
||||
<pre><code>let individualScores = [75, 43, 103, 87, 12]
|
||||
var teamScore = 0
|
||||
for score in individualScores {
|
||||
if score > 50 {
|
||||
teamScore += 3
|
||||
} else {
|
||||
teamScore += 1
|
||||
<pre><code class="lang-swift"> let individualScores = [75, 43, 103, 87, 12]
|
||||
var teamScore = 0
|
||||
for score in individualScores {
|
||||
if score > 50 {
|
||||
teamScore += 3
|
||||
} else {
|
||||
teamScore += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
teamScore
|
||||
</code></pre><p>在<code>if</code>语句中,条件必须是一个布尔表达式——这意味着像<code>if score { ... }</code>这样的代码将报错,而不会隐形地与 0 做对比。</p>
|
||||
teamScore
|
||||
</code></pre>
|
||||
<p>在<code>if</code>语句中,条件必须是一个布尔表达式——这意味着像<code>if score { ... }</code>这样的代码将报错,而不会隐形地与 0 做对比。</p>
|
||||
<p>你可以一起使用<code>if</code>和<code>let</code>来处理值缺失的情况。有些变量的值是可选的。一个可选的值可能是一个具体的值或者是<code>nil</code>,表示值缺失。在类型后面加一个问号来标记这个变量的值是可选的。</p>
|
||||
<pre><code>var optionalString: String? = "Hello"
|
||||
optionalString == nil
|
||||
<pre><code class="lang-swift"> var optionalString: String? = "Hello"
|
||||
optionalString == nil
|
||||
|
||||
var optionalName: String? = "John Appleseed"
|
||||
var greeting = "Hello!"
|
||||
if let name = optionalName {
|
||||
greeting = "Hello, \(name)"
|
||||
}
|
||||
</code></pre><blockquote>
|
||||
var optionalName: String? = "John Appleseed"
|
||||
var greeting = "Hello!"
|
||||
if let name = optionalName {
|
||||
greeting = "Hello, \(name)"
|
||||
}
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>练习:</p>
|
||||
<p>把<code>optionalName</code>改成<code>nil</code>,greeting会是什么?添加一个<code>else</code>语句,当<code>optionalName</code>是<code>nil</code>时给greeting赋一个不同的值。</p>
|
||||
</blockquote>
|
||||
<p>如果变量的可选值是<code>nil</code>,条件会判断为<code>false</code>,大括号中的代码会被跳过。如果不是<code>nil</code>,会将值赋给<code>let</code>后面的常量,这样代码块中就可以使用这个值了。</p>
|
||||
<p><code>switch</code>支持任意类型的数据以及各种比较操作——不仅仅是整数以及测试相等。</p>
|
||||
<pre><code>let vegetable = "red pepper"
|
||||
switch vegetable {
|
||||
case "celery":
|
||||
let vegetableComment = "Add some raisins and make ants on a log."
|
||||
case "cucumber", "watercress":
|
||||
let vegetableComment = "That would make a good tea sandwich."
|
||||
case let x where x.hasSuffix("pepper"):
|
||||
let vegetableComment = "Is it a spicy \(x)?"
|
||||
default:
|
||||
let vegetableComment = "Everything tastes good in soup."
|
||||
}
|
||||
</code></pre><blockquote>
|
||||
<pre><code class="lang-swift"> let vegetable = "red pepper"
|
||||
switch vegetable {
|
||||
case "celery":
|
||||
let vegetableComment = "Add some raisins and make ants on a log."
|
||||
case "cucumber", "watercress":
|
||||
let vegetableComment = "That would make a good tea sandwich."
|
||||
case let x where x.hasSuffix("pepper"):
|
||||
let vegetableComment = "Is it a spicy \(x)?"
|
||||
default:
|
||||
let vegetableComment = "Everything tastes good in soup."
|
||||
}
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>练习:</p>
|
||||
<p>删除<code>default</code>语句,看看会有什么错误?</p>
|
||||
</blockquote>
|
||||
<p>运行<code>switch</code>中匹配到的子句之后,程序会退出<code>switch</code>语句,并不会继续向下运行,所以不需要在每个子句结尾写<code>break</code>。</p>
|
||||
<p>你可以使用<code>for-in</code>来遍历字典,需要两个变量来表示每个键值对。</p>
|
||||
<pre><code>let interestingNumbers = [
|
||||
"Prime": [2, 3, 5, 7, 11, 13],
|
||||
"Fibonacci": [1, 1, 2, 3, 5, 8],
|
||||
"Square": [1, 4, 9, 16, 25],
|
||||
]
|
||||
var largest = 0
|
||||
for (kind, numbers) in interestingNumbers {
|
||||
for number in numbers {
|
||||
if number > largest {
|
||||
largest = number
|
||||
<pre><code class="lang-swift"> let interestingNumbers = [
|
||||
"Prime": [2, 3, 5, 7, 11, 13],
|
||||
"Fibonacci": [1, 1, 2, 3, 5, 8],
|
||||
"Square": [1, 4, 9, 16, 25],
|
||||
]
|
||||
var largest = 0
|
||||
for (kind, numbers) in interestingNumbers {
|
||||
for number in numbers {
|
||||
if number > largest {
|
||||
largest = number
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
largest
|
||||
</code></pre><blockquote>
|
||||
largest
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>练习:</p>
|
||||
<p>添加另一个变量来记录哪种类型的数字是最大的。</p>
|
||||
</blockquote>
|
||||
<p>使用<code>while</code>来重复运行一段代码直到不满足条件。循环条件可以在开头也可以在结尾。</p>
|
||||
<pre><code>var n = 2
|
||||
while n < 100 {
|
||||
n = n * 2
|
||||
}
|
||||
n
|
||||
<pre><code class="lang-swift"> var n = 2
|
||||
while n < 100 {
|
||||
n = n * 2
|
||||
}
|
||||
n
|
||||
|
||||
var m = 2
|
||||
do {
|
||||
m = m * 2
|
||||
} while m < 100
|
||||
m
|
||||
</code></pre><p>你可以在循环中使用<code>..</code>来表示范围,也可以使用传统的写法,两者是等价的:</p>
|
||||
<pre><code>var firstForLoop = 0
|
||||
for i in 0..3 {
|
||||
firstForLoop += i
|
||||
}
|
||||
firstForLoop
|
||||
var m = 2
|
||||
do {
|
||||
m = m * 2
|
||||
} while m < 100
|
||||
m
|
||||
</code></pre>
|
||||
<p>你可以在循环中使用<code>..</code>来表示范围,也可以使用传统的写法,两者是等价的:</p>
|
||||
<pre><code class="lang-swift"> var firstForLoop = 0
|
||||
for i in 0..3 {
|
||||
firstForLoop += i
|
||||
}
|
||||
firstForLoop
|
||||
|
||||
var secondForLoop = 0
|
||||
for var i = 0; i < 3; ++i {
|
||||
secondForLoop += 1
|
||||
}
|
||||
secondForLoop
|
||||
</code></pre><p>使用<code>..</code>创建的范围不包含上界,如果想包含的话需要使用<code>...</code>。</p>
|
||||
var secondForLoop = 0
|
||||
for var i = 0; i < 3; ++i {
|
||||
secondForLoop += 1
|
||||
}
|
||||
secondForLoop
|
||||
</code></pre>
|
||||
<p>使用<code>..</code>创建的范围不包含上界,如果想包含的话需要使用<code>...</code>。</p>
|
||||
<p><a name="functions_and_closures"></a></p>
|
||||
<h2 id="-">函数和闭包</h2>
|
||||
<p>使用<code>func</code>来声明一个函数,使用名字和参数来调用函数。使用<code>-></code>来指定函数返回值。</p>
|
||||
<pre><code>func greet(name: String, day: String) -> String {
|
||||
return "Hello \(name), today is \(day)."
|
||||
}
|
||||
greet("Bob", "Tuesday")
|
||||
</code></pre><blockquote>
|
||||
<pre><code class="lang-swift"> func greet(name: String, day: String) -> String {
|
||||
return "Hello \(name), today is \(day)."
|
||||
}
|
||||
greet("Bob", "Tuesday")
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>练习:</p>
|
||||
<p>删除<code>day</code>参数,添加一个参数来表示今天吃了什么午饭。</p>
|
||||
</blockquote>
|
||||
<p>使用一个元组来返回多个值。</p>
|
||||
<pre><code>func getGasPrices() -> (Double, Double, Double) {
|
||||
return (3.59, 3.69, 3.79)
|
||||
}
|
||||
getGasPrices()
|
||||
</code></pre><p>函数的参数数量是可变的,用一个数组来获取它们:</p>
|
||||
<pre><code>func sumOf(numbers: Int...) -> Int {
|
||||
var sum = 0
|
||||
for number in numbers {
|
||||
sum += number
|
||||
<pre><code class="lang-swift"> func getGasPrices() -> (Double, Double, Double) {
|
||||
return (3.59, 3.69, 3.79)
|
||||
}
|
||||
return sum
|
||||
}
|
||||
sumOf()
|
||||
sumOf(42, 597, 12)
|
||||
</code></pre><blockquote>
|
||||
getGasPrices()
|
||||
</code></pre>
|
||||
<p>函数的参数数量是可变的,用一个数组来获取它们:</p>
|
||||
<pre><code class="lang-swift"> func sumOf(numbers: Int...) -> Int {
|
||||
var sum = 0
|
||||
for number in numbers {
|
||||
sum += number
|
||||
}
|
||||
return sum
|
||||
}
|
||||
sumOf()
|
||||
sumOf(42, 597, 12)
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>练习:</p>
|
||||
<p>写一个计算参数平均值的函数。</p>
|
||||
</blockquote>
|
||||
<p>函数可以嵌套。被嵌套的函数可以访问外侧函数的变量,你可以使用嵌套函数来重构一个太长或者太复杂的函数。</p>
|
||||
<pre><code>func returnFifteen() -> Int {
|
||||
var y = 10
|
||||
func add() {
|
||||
y += 5
|
||||
}
|
||||
add()
|
||||
return y
|
||||
}
|
||||
returnFifteen()
|
||||
</code></pre><p>函数是一等公民,这意味着函数可以作为另一个函数的返回值。</p>
|
||||
<pre><code>func makeIncrementer() -> (Int -> Int) {
|
||||
func addOne(number: Int) -> Int {
|
||||
return 1 + number
|
||||
}
|
||||
return addOne
|
||||
}
|
||||
var increment = makeIncrementer()
|
||||
increment(7)
|
||||
</code></pre><p>函数也可以当做参数传入另一个函数。</p>
|
||||
<pre><code>func hasAnyMatches(list: Int[], condition: Int -> Bool) -> Bool {
|
||||
for item in list {
|
||||
if condition(item) {
|
||||
return true
|
||||
<pre><code class="lang-swift"> func returnFifteen() -> Int {
|
||||
var y = 10
|
||||
func add() {
|
||||
y += 5
|
||||
}
|
||||
add()
|
||||
return y
|
||||
}
|
||||
return false
|
||||
}
|
||||
func lessThanTen(number: Int) -> Bool {
|
||||
return number < 10
|
||||
}
|
||||
var numbers = [20, 19, 7, 12]
|
||||
hasAnyMatches(numbers, lessThanTen)
|
||||
</code></pre><p>函数实际上是一种特殊的闭包,你可以使用<code>{}</code>来创建一个匿名闭包。使用<code>in</code>将参数和返回值类型声明与闭包函数体进行分离。</p>
|
||||
<pre><code>numbers.map({
|
||||
(number: Int) -> Int in
|
||||
let result = 3 * number
|
||||
return result
|
||||
})
|
||||
</code></pre><blockquote>
|
||||
returnFifteen()
|
||||
</code></pre>
|
||||
<p>函数是第一等类型,这意味着函数可以作为另一个函数的返回值。</p>
|
||||
<pre><code class="lang-swift"> func makeIncrementer() -> (Int -> Int) {
|
||||
func addOne(number: Int) -> Int {
|
||||
return 1 + number
|
||||
}
|
||||
return addOne
|
||||
}
|
||||
var increment = makeIncrementer()
|
||||
increment(7)
|
||||
</code></pre>
|
||||
<p>函数也可以当做参数传入另一个函数。</p>
|
||||
<pre><code class="lang-swift"> func hasAnyMatches(list: Int[], condition: Int -> Bool) -> Bool {
|
||||
for item in list {
|
||||
if condition(item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
func lessThanTen(number: Int) -> Bool {
|
||||
return number < 10
|
||||
}
|
||||
var numbers = [20, 19, 7, 12]
|
||||
hasAnyMatches(numbers, lessThanTen)
|
||||
</code></pre>
|
||||
<p>函数实际上是一种特殊的闭包,你可以使用<code>{}</code>来创建一个匿名闭包。使用<code>in</code>将参数和返回值类型声明与闭包函数体进行分离。</p>
|
||||
<pre><code class="lang-swift"> numbers.map({
|
||||
(number: Int) -> Int in
|
||||
let result = 3 * number
|
||||
return result
|
||||
})
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>练习:</p>
|
||||
<p>重写闭包,对所有奇数返回 0.</p>
|
||||
</blockquote>
|
||||
<p>有很多种创建闭包的方法。如果一个闭包的类型已知,比如作为一个回调函数,你可以忽略参数的类型和返回值。单个语句闭包会把它语句的值当做结果返回。</p>
|
||||
<pre><code>numbers.map({ number in 3 * number })
|
||||
</code></pre><p>你可以通过参数位置而不是参数名字来引用参数——这个方法在非常短的闭包中非常有用。当一个闭包作为最后一个参数传给一个函数的时候,它可以直接跟在括号后面。</p>
|
||||
<pre><code>sort([1, 5, 3, 12, 2]) { $0 > $1 }
|
||||
</code></pre><p><a name="objects_and_classes"></a></p>
|
||||
<pre><code class="lang-swift"> numbers.map({ number in 3 * number })
|
||||
</code></pre>
|
||||
<p>你可以通过参数位置而不是参数名字来引用参数——这个方法在非常短的闭包中非常有用。当一个闭包作为最后一个参数传给一个函数的时候,它可以直接跟在括号后面。</p>
|
||||
<pre><code class="lang-swift"> sort([1, 5, 3, 12, 2]) { $0 > $1 }
|
||||
</code></pre>
|
||||
<p><a name="objects_and_classes"></a></p>
|
||||
<h2 id="-">对象和类</h2>
|
||||
<p>使用<code>class</code>和类名来创建一个类。类中属性的声明和常量、变量声明一样,唯一的区别就是它们的上下文是类。同样,方法和函数声明也一样。</p>
|
||||
<pre><code>class Shape {
|
||||
var numberOfSides = 0
|
||||
func simpleDescription() -> String {
|
||||
return "A shape with \(numberOfSides) sides."
|
||||
<pre><code class="lang-swift"> class Shape {
|
||||
var numberOfSides = 0
|
||||
func simpleDescription() -> String {
|
||||
return "A shape with \(numberOfSides) sides."
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre><blockquote>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>练习:</p>
|
||||
<p>使用<code>let</code>添加一个常量属性,再添加一个接收一个参数的方法。</p>
|
||||
</blockquote>
|
||||
<p>要创建一个类的实例,在类名后面加上括号。使用点语法来访问实例的属性和方法。</p>
|
||||
<pre><code>var shape = Shape()
|
||||
shape.numberOfSides = 7
|
||||
var shapeDescription = shape.simpleDescription()
|
||||
</code></pre><p>这个版本的<code>Shape</code>类缺少了一些重要的东西:一个构造函数来初始化类实例。使用<code>init</code>来创建一个构造器。</p>
|
||||
<pre><code>class NamedShape {
|
||||
var numberOfSides: Int = 0
|
||||
var name: String
|
||||
<pre><code class="lang-swift"> var shape = Shape()
|
||||
shape.numberOfSides = 7
|
||||
var shapeDescription = shape.simpleDescription()
|
||||
</code></pre>
|
||||
<p>这个版本的<code>Shape</code>类缺少了一些重要的东西:一个构造函数来初始化类实例。使用<code>init</code>来创建一个构造器。</p>
|
||||
<pre><code class="lang-swift"> class NamedShape {
|
||||
var numberOfSides: Int = 0
|
||||
var name: String
|
||||
|
||||
init(name: String) {
|
||||
self.name = name
|
||||
}
|
||||
init(name: String) {
|
||||
self.name = name
|
||||
}
|
||||
|
||||
func simpleDescription() -> String {
|
||||
return "A shape with \(numberOfSides) sides."
|
||||
func simpleDescription() -> String {
|
||||
return "A shape with \(numberOfSides) sides."
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre><p>注意<code>self</code>被用来区别实例变量。当你创建实例的时候,像传入函数参数一样给类传入构造器的参数。每个属性都需要赋值——无论是通过声明(就像<code>numberOfSides</code>)还是通过构造器(就像<code>name</code>)。</p>
|
||||
</code></pre>
|
||||
<p>注意<code>self</code>被用来区别实例变量。当你创建实例的时候,像传入函数参数一样给类传入构造器的参数。每个属性都需要赋值——无论是通过声明(就像<code>numberOfSides</code>)还是通过构造器(就像<code>name</code>)。</p>
|
||||
<p>如果你需要在删除对象之前进行一些清理工作,使用<code>deinit</code>创建一个析构函数。</p>
|
||||
<p>子类的定义方法是在它们的类名后面加上父类的名字,用冒号分割。创建类的时候并不需要一个标准的根类,所以你可以忽略父类。</p>
|
||||
<p>子类如果要重写父类的方法的话,需要用<code>override</code>标记——如果没有添加<code>override</code>就重写父类方法的话编译器会报错。编译器同样会检测<code>override</code>标记的方法是否确实在父类中。</p>
|
||||
<pre><code>class Square: NamedShape {
|
||||
var sideLength: Double
|
||||
<pre><code class="lang-swift"> class Square: NamedShape {
|
||||
var sideLength: Double
|
||||
|
||||
init(sideLength: Double, name: String) {
|
||||
self.sideLength = sideLength
|
||||
super.init(name: name)
|
||||
numberOfSides = 4
|
||||
}
|
||||
init(sideLength: Double, name: String) {
|
||||
self.sideLength = sideLength
|
||||
super.init(name: name)
|
||||
numberOfSides = 4
|
||||
}
|
||||
|
||||
func area() -> Double {
|
||||
return sideLength * sideLength
|
||||
}
|
||||
func area() -> Double {
|
||||
return sideLength * sideLength
|
||||
}
|
||||
|
||||
override func simpleDescription() -> String {
|
||||
return "A square with sides of length \(sideLength)."
|
||||
override func simpleDescription() -> String {
|
||||
return "A square with sides of length \(sideLength)."
|
||||
}
|
||||
}
|
||||
}
|
||||
let test = Square(sideLength: 5.2, name: "my test square")
|
||||
test.area()
|
||||
test.simpleDescription()
|
||||
</code></pre><blockquote>
|
||||
let test = Square(sideLength: 5.2, name: "my test square")
|
||||
test.area()
|
||||
test.simpleDescription()
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>练习:</p>
|
||||
<p>创建<code>NamedShape</code>的另一个子类<code>Circle</code>,构造器接收两个参数,一个是半径一个是名称,实现<code>area</code>和<code>describe</code>方法。</p>
|
||||
</blockquote>
|
||||
<p>属性可以有 getter 和 setter 。</p>
|
||||
<pre><code>class EquilateralTriangle: NamedShape {
|
||||
var sideLength: Double = 0.0
|
||||
<pre><code class="lang-swift"> class EquilateralTriangle: NamedShape {
|
||||
var sideLength: Double = 0.0
|
||||
|
||||
init(sideLength: Double, name: String) {
|
||||
self.sideLength = sideLength
|
||||
super.init(name: name)
|
||||
numberOfSides = 3
|
||||
}
|
||||
init(sideLength: Double, name: String) {
|
||||
self.sideLength = sideLength
|
||||
super.init(name: name)
|
||||
numberOfSides = 3
|
||||
}
|
||||
|
||||
var perimeter: Double {
|
||||
get {
|
||||
return 3.0 * sideLength
|
||||
}
|
||||
set {
|
||||
sideLength = newValue / 3.0
|
||||
}
|
||||
}
|
||||
var perimeter: Double {
|
||||
get {
|
||||
return 3.0 * sideLength
|
||||
}
|
||||
set {
|
||||
sideLength = newValue / 3.0
|
||||
}
|
||||
}
|
||||
|
||||
override func simpleDescription() -> String {
|
||||
return "An equilateral triagle with sides of length \(sideLength)."
|
||||
override func simpleDescription() -> String {
|
||||
return "An equilateral triagle with sides of length \(sideLength)."
|
||||
}
|
||||
}
|
||||
}
|
||||
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
|
||||
triangle.perimeter
|
||||
triangle.perimeter = 9.9
|
||||
triangle.sideLength
|
||||
</code></pre><p>在<code>perimeter</code>的 setter 中,新值的名字是<code>newValue</code>。你可以在<code>set</code>之后显式的设置一个名字。</p>
|
||||
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
|
||||
triangle.perimeter
|
||||
triangle.perimeter = 9.9
|
||||
triangle.sideLength
|
||||
</code></pre>
|
||||
<p>在<code>perimeter</code>的 setter 中,新值的名字是<code>newValue</code>。你可以在<code>set</code>之后显式的设置一个名字。</p>
|
||||
<p>注意<code>EquilateralTriangle</code>类的构造器执行了三步:</p>
|
||||
<ol>
|
||||
<li>设置子类声明的属性值</li>
|
||||
@ -919,129 +947,137 @@ triangle.sideLength
|
||||
</ol>
|
||||
<p>如果你不需要计算属性但是需要在设置一个新值之前运行一些代码,使用<code>willSet</code>和<code>didSet</code>。</p>
|
||||
<p>比如,下面的类确保三角形的边长总是和正方形的边长相同。</p>
|
||||
<pre><code>class TriangleAndSquare {
|
||||
var triangle: EquilateralTriangle {
|
||||
willSet {
|
||||
square.sideLength = newValue.sideLength
|
||||
}
|
||||
}
|
||||
var square: Square {
|
||||
willSet {
|
||||
triangle.sideLength = newValue.sideLength
|
||||
}
|
||||
}
|
||||
init(size: Double, name: String) {
|
||||
square = Square(sideLength: size, name: name)
|
||||
triangle = EquilateralTriangle(sideLength: size, name: name)
|
||||
}
|
||||
}
|
||||
var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
|
||||
triangleAndSquare.square.sideLength
|
||||
triangleAndSquare.triangle.sideLength
|
||||
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
|
||||
triangleAndSquare.triangle.sideLength
|
||||
</code></pre><p>类中的方法和一般的函数有一个重要的区别,函数的参数名只在函数内部使用,但是方法的参数名需要在调用的时候显式说明(除了第一个参数)。默认情况下,方法的参数名和它在方法内部的名字一样,不过你也可以定义第二个名字,这个名字被用在方法内部。</p>
|
||||
<pre><code>class Counter {
|
||||
var count: Int = 0
|
||||
func incrementBy(amount: Int, numberOfTimes times: Int) {
|
||||
count += amount * times
|
||||
}
|
||||
}
|
||||
var counter = Counter()
|
||||
counter.incrementBy(2, numberOfTimes: 7)
|
||||
</code></pre><p>处理变量的可选值时,你可以在操作(比如方法、属性和子脚本)之前加<code>?</code>。如果<code>?</code>之前的值是<code>nil</code>,<code>?</code>后面的东西都会被忽略,并且整个表达式返回<code>nil</code>。否则,<code>?</code>之后的东西都会被运行。在这两种情况下,整个表达式的值也是一个可选值。</p>
|
||||
<pre><code>let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
|
||||
let sideLength = optionalSquare?.sideLength
|
||||
</code></pre><p><a name="enumerations_and_structure"></a></p>
|
||||
<h2 id="-">枚举和结构体</h2>
|
||||
<p>使用<code>enum</code>来创建一个枚举。就像类和其他所有命名类型一样,枚举可以包含方法。</p>
|
||||
<pre><code>enum Rank: Int {
|
||||
case Ace = 1
|
||||
case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
|
||||
case Jack, Queen, King
|
||||
func simpleDescription() -> String {
|
||||
switch self {
|
||||
case .Ace:
|
||||
return "ace"
|
||||
case .Jack:
|
||||
return "jack"
|
||||
case .Queen:
|
||||
return "queen"
|
||||
case .King:
|
||||
return "king"
|
||||
default:
|
||||
return String(self.toRaw())
|
||||
<pre><code class="lang-swift"> class TriangleAndSquare {
|
||||
var triangle: EquilateralTriangle {
|
||||
willSet {
|
||||
square.sideLength = newValue.sideLength
|
||||
}
|
||||
}
|
||||
var square: Square {
|
||||
willSet {
|
||||
triangle.sideLength = newValue.sideLength
|
||||
}
|
||||
}
|
||||
init(size: Double, name: String) {
|
||||
square = Square(sideLength: size, name: name)
|
||||
triangle = EquilateralTriangle(sideLength: size, name: name)
|
||||
}
|
||||
}
|
||||
}
|
||||
let ace = Rank.Ace
|
||||
let aceRawValue = ace.toRaw()
|
||||
</code></pre><blockquote>
|
||||
var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
|
||||
triangleAndSquare.square.sideLength
|
||||
triangleAndSquare.triangle.sideLength
|
||||
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
|
||||
triangleAndSquare.triangle.sideLength
|
||||
</code></pre>
|
||||
<p>类中的方法和一般的函数有一个重要的区别,函数的参数名只在函数内部使用,但是方法的参数名需要在调用的时候显式说明(除了第一个参数)。默认情况下,方法的参数名和它在方法内部的名字一样,不过你也可以定义第二个名字,这个名字被用在方法内部。</p>
|
||||
<pre><code class="lang-swift"> class Counter {
|
||||
var count: Int = 0
|
||||
func incrementBy(amount: Int, numberOfTimes times: Int) {
|
||||
count += amount * times
|
||||
}
|
||||
}
|
||||
var counter = Counter()
|
||||
counter.incrementBy(2, numberOfTimes: 7)
|
||||
</code></pre>
|
||||
<p>处理变量的可选值时,你可以在操作(比如方法、属性和子脚本)之前加<code>?</code>。如果<code>?</code>之前的值是<code>nil</code>,<code>?</code>后面的东西都会被忽略,并且整个表达式返回<code>nil</code>。否则,<code>?</code>之后的东西都会被运行。在这两种情况下,整个表达式的值也是一个可选值。</p>
|
||||
<pre><code class="lang-swift"> let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
|
||||
let sideLength = optionalSquare?.sideLength
|
||||
</code></pre>
|
||||
<p><a name="enumerations_and_structure"></a></p>
|
||||
<h2 id="-">枚举和结构体</h2>
|
||||
<p>使用<code>enum</code>来创建一个枚举。就像类和其他所有命名类型一样,枚举可以包含方法。</p>
|
||||
<pre><code class="lang-swift"> enum Rank: Int {
|
||||
case Ace = 1
|
||||
case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
|
||||
case Jack, Queen, King
|
||||
func simpleDescription() -> String {
|
||||
switch self {
|
||||
case .Ace:
|
||||
return "ace"
|
||||
case .Jack:
|
||||
return "jack"
|
||||
case .Queen:
|
||||
return "queen"
|
||||
case .King:
|
||||
return "king"
|
||||
default:
|
||||
return String(self.toRaw())
|
||||
}
|
||||
}
|
||||
}
|
||||
let ace = Rank.Ace
|
||||
let aceRawValue = ace.toRaw()
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>练习:</p>
|
||||
<p>写一个函数,通过比较它们的原始值来比较两个<code>Rank</code>值。</p>
|
||||
</blockquote>
|
||||
<p>在上面的例子中,枚举原始值的类型是<code>Int</code>,所以你只需要设置第一个原始值。剩下的原始值会按照顺序赋值。你也可以使用字符串或者浮点数作为枚举的原始值。</p>
|
||||
<p>使用<code>toRaw</code>和<code>fromRaw</code>函数来在原始值和枚举值之间进行转换。</p>
|
||||
<pre><code>if let convertedRank = Rank.fromRaw(3) {
|
||||
let threeDescription = convertedRank.simpleDescription()
|
||||
}
|
||||
</code></pre><p>枚举的成员值是实际值,并不是原始值的另一种表达方法。实际上,如果原始值没有意义,你不需要设置。</p>
|
||||
<pre><code>enum Suit {
|
||||
case Spades, Hearts, Diamonds, Clubs
|
||||
func simpleDescription() -> String {
|
||||
switch self {
|
||||
case .Spades:
|
||||
return "spades"
|
||||
case .Hearts:
|
||||
return "hearts"
|
||||
case .Diamonds:
|
||||
return "diamonds"
|
||||
case .Clubs:
|
||||
return "clubs"
|
||||
}
|
||||
<pre><code class="lang-swift"> if let convertedRank = Rank.fromRaw(3) {
|
||||
let threeDescription = convertedRank.simpleDescription()
|
||||
}
|
||||
</code></pre>
|
||||
<p>枚举的成员值是实际值,并不是原始值的另一种表达方法。实际上,如果原始值没有意义,你不需要设置。</p>
|
||||
<pre><code class="lang-swift"> enum Suit {
|
||||
case Spades, Hearts, Diamonds, Clubs
|
||||
func simpleDescription() -> String {
|
||||
switch self {
|
||||
case .Spades:
|
||||
return "spades"
|
||||
case .Hearts:
|
||||
return "hearts"
|
||||
case .Diamonds:
|
||||
return "diamonds"
|
||||
case .Clubs:
|
||||
return "clubs"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
let hearts = Suit.Hearts
|
||||
let heartsDescription = hearts.simpleDescription()
|
||||
</code></pre><blockquote>
|
||||
}
|
||||
let hearts = Suit.Hearts
|
||||
let heartsDescription = hearts.simpleDescription()
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>练习:</p>
|
||||
<p>给<code>Suit</code>添加一个<code>color</code>方法,对<code>spades</code>和<code>clubs</code>返回“black”,对<code>hearts</code>和<code>diamonds</code>返回“red”。</p>
|
||||
</blockquote>
|
||||
<p>注意,有两种方式可以引用<code>Hearts</code>成员:给<code>hearts</code>常量赋值时,枚举成员<code>Suit.Hearts</code>需要用全名来引用,因为常量没有显式指定类型。在<code>switch</code>里,枚举成员使用缩写<code>.Hearts</code>来引用,因为<code>self</code>的值已经知道是一个<code>suit</code>。已知变量类型的情况下你可以使用缩写。</p>
|
||||
<p>使用<code>struct</code>来创建一个结构体。结构体和类有很多相同的地方,比如方法和构造器。它们之间最大的一个区别就是
|
||||
结构体是传值,类是传引用。</p>
|
||||
<pre><code>struct Card {
|
||||
var rank: Rank
|
||||
var suit: Suit
|
||||
func simpleDescription() -> String {
|
||||
return "The \(rank.simpleDescription()) of \
|
||||
(suit.simpleDescription())"
|
||||
<pre><code class="lang-swift"> struct Card {
|
||||
var rank: Rank
|
||||
var suit: Suit
|
||||
func simpleDescription() -> String {
|
||||
return "The \(rank.simpleDescription()) of \
|
||||
(suit.simpleDescription())"
|
||||
}
|
||||
}
|
||||
}
|
||||
let threeOfSpades = Card(rank: .Three, suit: .Spades)
|
||||
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
|
||||
</code></pre><blockquote>
|
||||
let threeOfSpades = Card(rank: .Three, suit: .Spades)
|
||||
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>练习:</p>
|
||||
<p>给<code>Card</code>添加一个方法,创建一副完整的扑克牌并把每张牌的 rank 和 suit 对应起来。</p>
|
||||
</blockquote>
|
||||
<p>一个枚举成员的实例可以有实例值。相同枚举成员的实例可以有不同的值。创建实例的时候传入值即可。实例值和原始值是不同的:枚举成员的原始值对于所有实例都是相同的,而且你是在定义枚举的时候设置原始值。</p>
|
||||
<p>例如,考虑从服务器获取日出和日落的时间。服务器会返回正常结果或者错误信息。</p>
|
||||
<pre><code>enum ServerResponse {
|
||||
case Result(String, String)
|
||||
case Error(String)
|
||||
}
|
||||
<pre><code class="lang-swift"> enum ServerResponse {
|
||||
case Result(String, String)
|
||||
case Error(String)
|
||||
}
|
||||
|
||||
let success = ServerResponse.Result("6:00 am", "8:09 pm")
|
||||
let failure = ServerResponse.Error("Out of cheese.")
|
||||
let success = ServerResponse.Result("6:00 am", "8:09 pm")
|
||||
let failure = ServerResponse.Error("Out of cheese.")
|
||||
|
||||
switch success {
|
||||
case let .Result(sunrise, sunset):
|
||||
let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)."
|
||||
case let .Error(error):
|
||||
let serverResponse = "Failure... \(error)"
|
||||
}
|
||||
</code></pre><blockquote>
|
||||
switch success {
|
||||
case let .Result(sunrise, sunset):
|
||||
let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)."
|
||||
case let .Error(error):
|
||||
let serverResponse = "Failure... \(error)"
|
||||
}
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>练习:</p>
|
||||
<p>给<code>ServerResponse</code>和<code>switch</code>添加第三种情况。</p>
|
||||
</blockquote>
|
||||
@ -1049,87 +1085,94 @@ case let .Error(error):
|
||||
<p><a name="protocols_and_extensions"></a></p>
|
||||
<h2 id="-">接口和扩展</h2>
|
||||
<p>使用<code>protocol</code>来声明一个接口。</p>
|
||||
<pre><code>protocol ExampleProtocol {
|
||||
var simpleDescription: String { get }
|
||||
mutating func adjust()
|
||||
}
|
||||
</code></pre><p>类、枚举和结构体都可以实现接口。</p>
|
||||
<pre><code>class SimpleClass: ExampleProtocol {
|
||||
var simpleDescription: String = "A very simple class."
|
||||
var anotherProperty: Int = 69105
|
||||
func adjust() {
|
||||
simpleDescription += " Now 100% adjusted."
|
||||
<pre><code class="lang-swift"> protocol ExampleProtocol {
|
||||
var simpleDescription: String { get }
|
||||
mutating func adjust()
|
||||
}
|
||||
}
|
||||
var a = SimpleClass()
|
||||
a.adjust()
|
||||
let aDescription = a.simpleDescription
|
||||
</code></pre>
|
||||
<p>类、枚举和结构体都可以实现接口。</p>
|
||||
<pre><code class="lang-swift"> class SimpleClass: ExampleProtocol {
|
||||
var simpleDescription: String = "A very simple class."
|
||||
var anotherProperty: Int = 69105
|
||||
func adjust() {
|
||||
simpleDescription += " Now 100% adjusted."
|
||||
}
|
||||
}
|
||||
var a = SimpleClass()
|
||||
a.adjust()
|
||||
let aDescription = a.simpleDescription
|
||||
|
||||
struct SimpleStructure: ExampleProtocol {
|
||||
var simpleDescription: String = "A simple structure"
|
||||
mutating func adjust() {
|
||||
simpleDescription += " (adjusted)"
|
||||
struct SimpleStructure: ExampleProtocol {
|
||||
var simpleDescription: String = "A simple structure"
|
||||
mutating func adjust() {
|
||||
simpleDescription += " (adjusted)"
|
||||
}
|
||||
}
|
||||
}
|
||||
var b = SimpleStructure()
|
||||
b.adjust()
|
||||
let bDescription = b.simpleDescription
|
||||
</code></pre><blockquote>
|
||||
var b = SimpleStructure()
|
||||
b.adjust()
|
||||
let bDescription = b.simpleDescription
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>练习:</p>
|
||||
<p>写一个实现这个接口的枚举。</p>
|
||||
</blockquote>
|
||||
<p>注意声明<code>SimpleStructure</code>时候<code>mutating</code>关键字用来标记一个会修改结构体的方法。<code>SimpleClass</code>的声明不需要标记任何方法因为类中的方法经常会修改类。</p>
|
||||
<p>使用<code>extension</code>来为现有的类型添加功能,比如添加一个计算属性的方法。你可以使用扩展来给任意类型添加协议,甚至是你从外部库或者框架中导入的类型。</p>
|
||||
<pre><code>extension Int: ExampleProtocol {
|
||||
var simpleDescription: String {
|
||||
return "The number \(self)"
|
||||
<pre><code class="lang-swift"> extension Int: ExampleProtocol {
|
||||
var simpleDescription: String {
|
||||
return "The number \(self)"
|
||||
}
|
||||
mutating func adjust() {
|
||||
self += 42
|
||||
}
|
||||
}
|
||||
mutating func adjust() {
|
||||
self += 42
|
||||
}
|
||||
}
|
||||
7.simpleDescription
|
||||
</code></pre><blockquote>
|
||||
7.simpleDescription
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>练习:</p>
|
||||
<p>给<code>Double</code>类型写一个扩展,添加<code>absoluteValue</code>功能。</p>
|
||||
</blockquote>
|
||||
<p>你可以像使用其他命名类型一样使用接口名——例如,创建一个有不同类型但是都实现一个接口的对象集合。当你处理类型是接口的值时,接口外定义的方法不可用。</p>
|
||||
<pre><code>let protocolValue: ExampleProtocol = a
|
||||
protocolValue.simpleDescription
|
||||
// protocolValue.anotherProperty // Uncomment to see the error
|
||||
</code></pre><p>即使<code>protocolValue</code>变量运行时的类型是<code>simpleClass</code>,编译器会把它的类型当做<code>ExampleProtocol</code>。这表示你不能调用类在它实现的接口之外实现的方法或者属性。</p>
|
||||
<pre><code class="lang-swift"> let protocolValue: ExampleProtocol = a
|
||||
protocolValue.simpleDescription
|
||||
// protocolValue.anotherProperty // Uncomment to see the error
|
||||
</code></pre>
|
||||
<p>即使<code>protocolValue</code>变量运行时的类型是<code>simpleClass</code>,编译器会把它的类型当做<code>ExampleProtocol</code>。这表示你不能调用类在它实现的接口之外实现的方法或者属性。</p>
|
||||
<p><a name="generics"></a></p>
|
||||
<h2 id="-">泛型</h2>
|
||||
<p>在尖括号里写一个名字来创建一个泛型函数或者类型。</p>
|
||||
<pre><code>func repeat<ItemType>(item: ItemType, times: Int) -> ItemType[] {
|
||||
var result = ItemType[]()
|
||||
for i in 0..times {
|
||||
result += item
|
||||
<pre><code class="lang-swift"> func repeat<ItemType>(item: ItemType, times: Int) -> ItemType[] {
|
||||
var result = ItemType[]()
|
||||
for i in 0..times {
|
||||
result += item
|
||||
}
|
||||
return result
|
||||
}
|
||||
return result
|
||||
}
|
||||
repeat("knock", 4)
|
||||
</code></pre><p>你也可以创建泛型类、枚举和结构体。</p>
|
||||
<pre><code>// Reimplement the Swift standard library's optional type
|
||||
enum OptionalValue<T> {
|
||||
case None
|
||||
case Some(T)
|
||||
}
|
||||
var possibleInteger: OptionalValue<Int> = .None
|
||||
possibleInteger = .Some(100)
|
||||
</code></pre><p>在类型名后面使用<code>where</code>来指定一个需求列表——例如,要限定实现一个协议的类型,需要限定两个类型要相同,或者限定一个类必须有一个特定的父类。</p>
|
||||
<pre><code>func anyCommonElements <T, U where T: Sequence, U: Sequence, T.GeneratorType.Element: Equatable, T.GeneratorType.Element == U.GeneratorType.Element> (lhs: T, rhs: U) -> Bool {
|
||||
for lhsItem in lhs {
|
||||
for rhsItem in rhs {
|
||||
if lhsItem == rhsItem {
|
||||
return true
|
||||
repeat("knock", 4)
|
||||
</code></pre>
|
||||
<p>你也可以创建泛型类、枚举和结构体。</p>
|
||||
<pre><code class="lang-swift"> // Reimplement the Swift standard library's optional type
|
||||
enum OptionalValue<T> {
|
||||
case None
|
||||
case Some(T)
|
||||
}
|
||||
var possibleInteger: OptionalValue<Int> = .None
|
||||
possibleInteger = .Some(100)
|
||||
</code></pre>
|
||||
<p>在类型名后面使用<code>where</code>来指定一个需求列表——例如,要限定实现一个协议的类型,需要限定两个类型要相同,或者限定一个类必须有一个特定的父类。</p>
|
||||
<pre><code class="lang-swift"> func anyCommonElements <T, U where T: Sequence, U: Sequence, T.GeneratorType.Element: Equatable, T.GeneratorType.Element == U.GeneratorType.Element> (lhs: T, rhs: U) -> Bool {
|
||||
for lhsItem in lhs {
|
||||
for rhsItem in rhs {
|
||||
if lhsItem == rhsItem {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
anyCommonElements([1, 2, 3], [3])
|
||||
</code></pre><blockquote>
|
||||
anyCommonElements([1, 2, 3], [3])
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>练习:</p>
|
||||
<p>修改<code>anyCommonElements</code>函数来创建一个函数,返回一个数组,内容是两个序列的共有元素。</p>
|
||||
</blockquote>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="1" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="1" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.1" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.1" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.2" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.2" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
@ -748,7 +748,7 @@ a += 2 // a 现在是 3
|
||||
<p>所有标准 C 语言中的比较运算都可以在 Swift 中使用。</p>
|
||||
<ul>
|
||||
<li>等于(<code>a == b</code>)</li>
|
||||
<li>不等于(<code>a!= b</code>)</li>
|
||||
<li>不等于(<code>a != b</code>)</li>
|
||||
<li>大于(<code>a > b</code>)</li>
|
||||
<li>小于(<code>a < b</code>)</li>
|
||||
<li>大于等于(<code>a >= b</code>)</li>
|
||||
@ -778,7 +778,7 @@ if name == "world" {
|
||||
<p>关于<code>if</code>语句,请看<a href="05_Control_Flow.html">控制流</a>。</p>
|
||||
<p><a name="ternary_conditional_operator"></a></p>
|
||||
<h2 id="-ternary-conditional-operator-">三元条件运算(Ternary Conditional Operator)</h2>
|
||||
<p>三元条件运算的特殊在于它是有三个操作数的运算符,它的原型是<code>问题?答案1:答案2</code>。它简洁地表达根据<code>问题</code>成立与否作出二选一的操作。如果<code>问题</code>成立,返回<code>答案1</code>的结果; 如果不成立,返回<code>答案2</code>的结果。</p>
|
||||
<p>三元条件运算的特殊在于它是有三个操作数的运算符,它的原型是 <code>问题 ? 答案1 : 答案2</code>。它简洁地表达根据<code>问题</code>成立与否作出二选一的操作。如果<code>问题</code>成立,返回<code>答案1</code>的结果; 如果不成立,返回<code>答案2</code>的结果。</p>
|
||||
<p>使用三元条件运算简化了以下代码:</p>
|
||||
<pre><code class="lang-swift">if question: {
|
||||
answer1
|
||||
@ -855,7 +855,7 @@ if !allowedEntry {
|
||||
}
|
||||
// 输出 "ACCESS DENIED"
|
||||
</code></pre>
|
||||
<p><code>if!allowedEntry</code>语句可以读作 "如果 非 alowed entry。",接下一行代码只有在如果 "非 allow entry" 为<code>true</code>,即<code>allowEntry</code>为<code>false</code>时被执行。</p>
|
||||
<p><code>if !allowedEntry</code>语句可以读作 "如果 非 alowed entry。",接下一行代码只有在如果 "非 allow entry" 为<code>true</code>,即<code>allowEntry</code>为<code>false</code>时被执行。</p>
|
||||
<p>在示例代码中,小心地选择布尔常量或变量有助于代码的可读性,并且避免使用双重逻辑非运算,或混乱的逻辑语句。</p>
|
||||
<h3 id="-">逻辑与</h3>
|
||||
<p>逻辑与(<code>a && b</code>)表达了只有<code>a</code>和<code>b</code>的值都为<code>true</code>时,整个表达式的值才会是<code>true</code>。</p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.3" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.3" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.4" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.4" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.5" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.5" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.6" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.6" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
@ -611,58 +611,64 @@
|
||||
<p>当你定义一个函数时,你可以定义一个或多个有名字和类型的值,作为函数的输入(称为参数,parameters),也可以定义某种类型的值作为函数执行结束的输出(称为返回类型)。</p>
|
||||
<p>每个函数有个函数名,用来描述函数执行的任务。要使用一个函数时,你用函数名“调用”,并传给它匹配的输入值(称作实参,arguments)。一个函数的实参必须与函数参数表里参数的顺序一致。</p>
|
||||
<p>在下面例子中的函数叫做<code>"greetingForPerson"</code>,之所以叫这个名字是因为这个函数用一个人的名字当做输入,并返回给这个人的问候语。为了完成这个任务,你定义一个输入参数-一个叫做 <code>personName</code> 的 <code>String</code> 值,和一个包含给这个人问候语的 <code>String</code> 类型的返回值:</p>
|
||||
<pre><code>func sayHello(personName: String) -> String {
|
||||
<pre><code class="lang-swift">func sayHello(personName: String) -> String {
|
||||
let greeting = "Hello, " + personName + "!"
|
||||
return greeting
|
||||
}
|
||||
</code></pre><p>所有的这些信息汇总起来成为函数的定义,并以 <code>func</code> 作为前缀。指定函数返回类型时,用返回箭头 <code>-></code>(一个连字符后跟一个右尖括号)后跟返回类型的名称的方式来表示。</p>
|
||||
</code></pre>
|
||||
<p>所有的这些信息汇总起来成为函数的定义,并以 <code>func</code> 作为前缀。指定函数返回类型时,用返回箭头 <code>-></code>(一个连字符后跟一个右尖括号)后跟返回类型的名称的方式来表示。</p>
|
||||
<p>该定义描述了函数做什么,它期望接收什么和执行结束时它返回的结果是什么。这样的定义使的函数可以在别的地方以一种清晰的方式被调用:</p>
|
||||
<pre><code>println(sayHello("Anna"))
|
||||
<pre><code class="lang-swift">println(sayHello("Anna"))
|
||||
// prints "Hello, Anna!"
|
||||
println(sayHello("Brian"))
|
||||
// prints "Hello, Brian!
|
||||
</code></pre><p>调用 <code>sayHello</code> 函数时,在圆括号中传给它一个 <code>String</code> 类型的实参。因为这个函数返回一个 <code>String</code> 类型的值,<code>sayHello</code> 可以被包含在 <code>println</code> 的调用中,用来输出这个函数的返回值,正如上面所示。</p>
|
||||
</code></pre>
|
||||
<p>调用 <code>sayHello</code> 函数时,在圆括号中传给它一个 <code>String</code> 类型的实参。因为这个函数返回一个 <code>String</code> 类型的值,<code>sayHello</code> 可以被包含在 <code>println</code> 的调用中,用来输出这个函数的返回值,正如上面所示。</p>
|
||||
<p>在 <code>sayHello</code> 的函数体中,先定义了一个新的名为 <code>greeting</code> 的 <code>String</code> 常量,同时赋值了给 <code>personName</code> 的一个简单问候消息。然后用 <code>return</code> 关键字把这个问候返回出去。一旦 <code>return greeting</code> 被调用,该函数结束它的执行并返回 <code>greeting</code> 的当前值。</p>
|
||||
<p>你可以用不同的输入值多次调用 <code>sayHello</code>。上面的例子展示的是用<code>"Anna"</code>和<code>"Brian"</code>调用的结果,该函数分别返回了不同的结果。</p>
|
||||
<p>为了简化这个函数的定义,可以将问候消息的创建和返回写成一句:</p>
|
||||
<pre><code>func sayHelloAgain(personName: String) -> String {
|
||||
<pre><code class="lang-swift">func sayHelloAgain(personName: String) -> String {
|
||||
return "Hello again, " + personName + "!"
|
||||
}
|
||||
println(sayHelloAgain("Anna"))
|
||||
// prints "Hello again, Anna!
|
||||
</code></pre><p><a name="Function_Parameters_and_Return_Values"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="Function_Parameters_and_Return_Values"></a></p>
|
||||
<h2 id="-function-parameters-and-return-values-">函数参数与返回值(Function Parameters and Return Values)</h2>
|
||||
<p>函数参数与返回值在Swift中极为灵活。你可以定义任何类型的函数,包括从只带一个未名参数的简单函数到复杂的带有表达性参数名和不同参数选项的复杂函数。</p>
|
||||
<h3 id="-multiple-input-parameters-">多重输入参数(Multiple Input Parameters)</h3>
|
||||
<p>函数可以有多个输入参数,写在圆括号中,用逗号分隔。</p>
|
||||
<p>下面这个函数用一个半开区间的开始点和结束点,计算出这个范围内包含多少数字:</p>
|
||||
<pre><code>func halfOpenRangeLength(start: Int, end: Int) -> Int {
|
||||
<pre><code class="lang-swift">func halfOpenRangeLength(start: Int, end: Int) -> Int {
|
||||
return end - start
|
||||
}
|
||||
println(halfOpenRangeLength(1, 10))
|
||||
// prints "9
|
||||
</code></pre><h3 id="-functions-without-parameters-">无参函数(Functions Without Parameters)</h3>
|
||||
</code></pre>
|
||||
<h3 id="-functions-without-parameters-">无参函数(Functions Without Parameters)</h3>
|
||||
<p>函数可以没有参数。下面这个函数就是一个无参函数,当被调用时,它返回固定的 <code>String</code> 消息:</p>
|
||||
<pre><code>func sayHelloWorld() -> String {
|
||||
<pre><code class="lang-swift">func sayHelloWorld() -> String {
|
||||
return "hello, world"
|
||||
}
|
||||
println(sayHelloWorld())
|
||||
// prints "hello, world
|
||||
</code></pre><p>尽管这个函数没有参数,但是定义中在函数名后还是需要一对圆括号。当被调用时,也需要在函数名后写一对圆括号。</p>
|
||||
</code></pre>
|
||||
<p>尽管这个函数没有参数,但是定义中在函数名后还是需要一对圆括号。当被调用时,也需要在函数名后写一对圆括号。</p>
|
||||
<h3 id="-functions-without-return-values-">无返回值函数(Functions Without Return Values)</h3>
|
||||
<p>函数可以没有返回值。下面是 <code>sayHello</code> 函数的另一个版本,叫 <code>waveGoodbye</code>,这个函数直接输出 <code>String</code> 值,而不是返回它:</p>
|
||||
<pre><code>func sayGoodbye(personName: String) {
|
||||
<pre><code class="lang-swift">func sayGoodbye(personName: String) {
|
||||
println("Goodbye, \(personName)!")
|
||||
}
|
||||
sayGoodbye("Dave")
|
||||
// prints "Goodbye, Dave!
|
||||
</code></pre><p>因为这个函数不需要返回值,所以这个函数的定义中没有返回箭头(->)和返回类型。</p>
|
||||
</code></pre>
|
||||
<p>因为这个函数不需要返回值,所以这个函数的定义中没有返回箭头(->)和返回类型。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>严格上来说,虽然没有返回值被定义,<code>sayGoodbye</code> 函数依然返回了值。没有定义返回类型的函数会返回特殊的值,叫 <code>Void</code>。它其实是一个空的元组(tuple),没有任何元素,可以写成<code>()</code>。</p>
|
||||
</blockquote>
|
||||
<p>被调用时,一个函数的返回值可以被忽略:</p>
|
||||
<pre><code>func printAndCount(stringToPrint: String) -> Int {
|
||||
<pre><code class="lang-swift">func printAndCount(stringToPrint: String) -> Int {
|
||||
println(stringToPrint)
|
||||
return countElements(stringToPrint)
|
||||
}
|
||||
@ -673,7 +679,8 @@ printAndCount("hello, world")
|
||||
// prints "hello, world" and returns a value of 12
|
||||
printWithoutCounting("hello, world")
|
||||
// prints "hello, world" but does not return a value
|
||||
</code></pre><p>第一个函数 <code>printAndCount</code>,输出一个字符串并返回 <code>Int</code> 类型的字符数。第二个函数 <code>printWithoutCounting</code>调用了第一个函数,但是忽略了它的返回值。当第二个函数被调用时,消息依然会由第一个函数输出,但是返回值不会被用到。</p>
|
||||
</code></pre>
|
||||
<p>第一个函数 <code>printAndCount</code>,输出一个字符串并返回 <code>Int</code> 类型的字符数。第二个函数 <code>printWithoutCounting</code>调用了第一个函数,但是忽略了它的返回值。当第二个函数被调用时,消息依然会由第一个函数输出,但是返回值不会被用到。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>返回值可以被忽略,但定义了有返回值的函数必须返回一个值,如果在函数定义底部没有返回任何值,这叫导致编译错误(compile-time error)。</p>
|
||||
@ -681,7 +688,7 @@ printWithoutCounting("hello, world")
|
||||
<h3 id="-functions-with-multiple-return-values-">多重返回值函数(Functions with Multiple Return Values)</h3>
|
||||
<p>你可以用元组(tuple)类型让多个值作为一个复合值从函数中返回。</p>
|
||||
<p>下面的这个例子中,<code>count</code> 函数用来计算一个字符串中元音,辅音和其他字母的个数(基于美式英语的标准)。</p>
|
||||
<pre><code>func count(string: String) -> (vowels: Int, consonants: Int, others: Int) {
|
||||
<pre><code class="lang-swift">func count(string: String) -> (vowels: Int, consonants: Int, others: Int) {
|
||||
var vowels = 0, consonants = 0, others = 0
|
||||
for character in string {
|
||||
switch String(character).lowercaseString {
|
||||
@ -696,7 +703,8 @@ printWithoutCounting("hello, world")
|
||||
}
|
||||
return (vowels, consonants, others)
|
||||
}
|
||||
</code></pre><p>你可以用 <code>count</code> 函数来处理任何一个字符串,返回的值将是一个包含三个 <code>Int</code> 型值的元组(tuple):</p>
|
||||
</code></pre>
|
||||
<p>你可以用 <code>count</code> 函数来处理任何一个字符串,返回的值将是一个包含三个 <code>Int</code> 型值的元组(tuple):</p>
|
||||
<pre><code>let total = count("some arbitrary string!")
|
||||
println("\(total.vowels) vowels and \(total.consonants) consonants")
|
||||
// prints "6 vowels and 13 consonants
|
||||
@ -704,38 +712,44 @@ println("\(total.vowels) vowels and \(total.consonants) consonants")
|
||||
<a name="Function_Parameter_Names"></a></p>
|
||||
<h2 id="-function-parameter-names-">函数参数名称(Function Parameter Names)</h2>
|
||||
<p>以上所有的函数都给它们的参数定义了<code>参数名(parameter name)</code>:</p>
|
||||
<pre><code>func someFunction(parameterName: Int) {
|
||||
<pre><code class="lang-swift">func someFunction(parameterName: Int) {
|
||||
// function body goes here, and can use parameterName
|
||||
// to refer to the argument value for that parameter
|
||||
}
|
||||
</code></pre><p>但是,这些参数名仅在函数体中使用,不能在函数调用时使用。这种类型的参数名被称作<code>局部参数名(local parameter name)</code>,因为它们只能在函数体中使用。</p>
|
||||
</code></pre>
|
||||
<p>但是,这些参数名仅在函数体中使用,不能在函数调用时使用。这种类型的参数名被称作<code>局部参数名(local parameter name)</code>,因为它们只能在函数体中使用。</p>
|
||||
<h3 id="-external-parameter-names-">外部参数名(External Parameter Names)</h3>
|
||||
<p>有时候,调用函数时,给每个参数命名是非常有用的,因为这些参数名可以指出各个实参的用途是什么。</p>
|
||||
<p>如果你希望函数的使用者在调用函数时提供参数名字,那就需要给每个参数除了局部参数名外再定义一个<code>外部参数名</code>。外部参数名写在局部参数名之前,用空格分隔。</p>
|
||||
<pre><code>func someFunction(externalParameterName localParameterName: Int) {
|
||||
<pre><code class="lang-swift">func someFunction(externalParameterName localParameterName: Int) {
|
||||
// function body goes here, and can use localParameterName
|
||||
// to refer to the argument value for that parameter
|
||||
}
|
||||
</code></pre><blockquote>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>如果你提供了外部参数名,那么函数在被调用时,必须使用外部参数名。</p>
|
||||
</blockquote>
|
||||
<p>以下是个例子,这个函数使用一个<code>结合者(joiner)</code>把两个字符串联在一起:</p>
|
||||
<pre><code>func join(s1: String, s2: String, joiner: String) -> String {
|
||||
<pre><code class="lang-swift">func join(s1: String, s2: String, joiner: String) -> String {
|
||||
return s1 + joiner + s2
|
||||
}
|
||||
</code></pre><p>当你调用这个函数时,这三个字符串的用途是不清楚的:</p>
|
||||
<pre><code>join("hello", "world", ", ")
|
||||
</code></pre>
|
||||
<p>当你调用这个函数时,这三个字符串的用途是不清楚的:</p>
|
||||
<pre><code class="lang-swift">join("hello", "world", ", ")
|
||||
// returns "hello, world
|
||||
</code></pre><p>为了让这些字符串的用途更为明显,我们为 <code>join</code> 函数添加外部参数名:</p>
|
||||
<pre><code>func join(string s1: String, toString s2: String, withJoiner joiner: String) -> String {
|
||||
</code></pre>
|
||||
<p>为了让这些字符串的用途更为明显,我们为 <code>join</code> 函数添加外部参数名:</p>
|
||||
<pre><code class="lang-swift">func join(string s1: String, toString s2: String, withJoiner joiner: String) -> String {
|
||||
return s1 + joiner + s2
|
||||
}
|
||||
</code></pre><p>在这个版本的 <code>join</code> 函数中,第一个参数有一个叫 <code>string</code> 的外部参数名和 <code>s1</code> 的局部参数名,第二个参数有一个叫 <code>toString</code> 的外部参数名和 <code>s2</code> 的局部参数名,第三个参数有一个叫 <code>withJoiner</code> 的外部参数名和 <code>joiner</code> 的局部参数名。</p>
|
||||
</code></pre>
|
||||
<p>在这个版本的 <code>join</code> 函数中,第一个参数有一个叫 <code>string</code> 的外部参数名和 <code>s1</code> 的局部参数名,第二个参数有一个叫 <code>toString</code> 的外部参数名和 <code>s2</code> 的局部参数名,第三个参数有一个叫 <code>withJoiner</code> 的外部参数名和 <code>joiner</code> 的局部参数名。</p>
|
||||
<p>现在,你可以使用这些外部参数名以一种清晰地方式来调用函数了:</p>
|
||||
<pre><code>join(string: "hello", toString: "world", withJoiner: ", ")
|
||||
<pre><code class="lang-swift">join(string: "hello", toString: "world", withJoiner: ", ")
|
||||
// returns "hello, world
|
||||
</code></pre><p>使用外部参数名让第二个版本的 <code>join</code> 函数的调用更为有表现力,更为通顺,同时还保持了函数体是可读的和有明确意图的。</p>
|
||||
</code></pre>
|
||||
<p>使用外部参数名让第二个版本的 <code>join</code> 函数的调用更为有表现力,更为通顺,同时还保持了函数体是可读的和有明确意图的。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>当其他人在第一次读你的代码,函数参数的意图显得不明显时,考虑使用外部参数名。如果函数参数名的意图是很明显的,那就不需要定义外部参数名了。</p>
|
||||
@ -743,7 +757,7 @@ println("\(total.vowels) vowels and \(total.consonants) consonants")
|
||||
<h3 id="-shorthand-external-parameter-names-">简写外部参数名(Shorthand External Parameter Names)</h3>
|
||||
<p>如果你需要提供外部参数名,但是局部参数名已经定义好了,那么你不需要写两次这些参数名。相反,只写一次参数名,并用<code>井号(#)</code>作为前缀就可以了。这告诉 Swift 使用这个参数名作为局部和外部参数名。</p>
|
||||
<p>下面这个例子定义了一个叫 <code>containsCharacter</code> 的函数,使用<code>井号(#)</code>的方式定义了外部参数名:</p>
|
||||
<pre><code>func containsCharacter(#string: String, #characterToFind: Character) -> Bool {
|
||||
<pre><code class="lang-swift">func containsCharacter(#string: String, #characterToFind: Character) -> Bool {
|
||||
for character in string {
|
||||
if character == characterToFind {
|
||||
return true
|
||||
@ -751,36 +765,43 @@ println("\(total.vowels) vowels and \(total.consonants) consonants")
|
||||
}
|
||||
return false
|
||||
}
|
||||
</code></pre><p>这样定义参数名,使得函数体更为可读,清晰,同时也可以以一个不含糊的方式被调用:</p>
|
||||
<pre><code>let containsAVee = containsCharacter(string: "aardvark", characterToFind: "v")
|
||||
</code></pre>
|
||||
<p>这样定义参数名,使得函数体更为可读,清晰,同时也可以以一个不含糊的方式被调用:</p>
|
||||
<pre><code class="lang-swift">let containsAVee = containsCharacter(string: "aardvark", characterToFind: "v")
|
||||
// containsAVee equals true, because "aardvark" contains a "v”
|
||||
</code></pre><h3 id="-default-parameter-values-">默认参数值(Default Parameter Values)</h3>
|
||||
</code></pre>
|
||||
<h3 id="-default-parameter-values-">默认参数值(Default Parameter Values)</h3>
|
||||
<p>你可以在函数体中为每个参数定义<code>默认值</code>。当默认值被定义后,调用这个函数时可以略去这个参数。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>将带有默认值的参数放在函数参数表的最后。这样可以保证在函数调用时,非默认参数的顺序是一致的,同时使得相同的函数在不同情况下调用时显得更为清晰。</p>
|
||||
</blockquote>
|
||||
<p>以下是另一个版本的<code>join</code>函数,其中<code>joiner</code>有了默认参数值:</p>
|
||||
<pre><code>func join(string s1: String, toString s2: String, withJoiner joiner: String = " ") -> String {
|
||||
<pre><code class="lang-swift">func join(string s1: String, toString s2: String, withJoiner joiner: String = " ") -> String {
|
||||
return s1 + joiner + s2
|
||||
}
|
||||
</code></pre><p>像第一个版本的 <code>join</code> 函数一样,如果 <code>joiner</code> 被赋值时,函数将使用这个字符串值来连接两个字符串:</p>
|
||||
<pre><code>join(string: "hello", toString: "world", withJoiner: "-")
|
||||
</code></pre>
|
||||
<p>像第一个版本的 <code>join</code> 函数一样,如果 <code>joiner</code> 被赋值时,函数将使用这个字符串值来连接两个字符串:</p>
|
||||
<pre><code class="lang-swift">join(string: "hello", toString: "world", withJoiner: "-")
|
||||
// returns "hello-world
|
||||
</code></pre><p>当这个函数被调用时,如果 <code>joiner</code> 的值没有被指定,函数会使用默认值(" "):</p>
|
||||
<pre><code>join(string: "hello", toString:"world")
|
||||
</code></pre>
|
||||
<p>当这个函数被调用时,如果 <code>joiner</code> 的值没有被指定,函数会使用默认值(" "):</p>
|
||||
<pre><code class="lang-swift">join(string: "hello", toString:"world")
|
||||
// returns "hello world"
|
||||
</code></pre><h3 id="-external-names-for-parameters-with-default-values-">默认值参数的外部参数名(External Names for Parameters with Default Values)</h3>
|
||||
</code></pre>
|
||||
<h3 id="-external-names-for-parameters-with-default-values-">默认值参数的外部参数名(External Names for Parameters with Default Values)</h3>
|
||||
<p>在大多数情况下,给带默认值的参数起一个外部参数名是很有用的。这样可以保证当函数被调用且带默认值的参数被提供值时,实参的意图是明显的。</p>
|
||||
<p>为了使定义外部参数名更加简单,当你未给带默认值的参数提供外部参数名时,Swift 会自动提供外部名字。此时外部参数名与局部名字是一样的,就像你已经在局部参数名前写了<code>井号(#)</code>一样。</p>
|
||||
<p>下面是 <code>join</code> 函数的另一个版本,这个版本中并没有为它的参数提供外部参数名,但是 <code>joiner</code> 参数依然有外部参数名:</p>
|
||||
<pre><code>func join(s1: String, s2: String, joiner: String = " ") -> String {
|
||||
<pre><code class="lang-swift">func join(s1: String, s2: String, joiner: String = " ") -> String {
|
||||
return s1 + joiner + s2
|
||||
}
|
||||
</code></pre><p>在这个例子中,Swift 自动为 <code>joiner</code> 提供了外部参数名。因此,当函数调用时,外部参数名必须使用,这样使得参数的用途变得清晰。</p>
|
||||
<pre><code>join("hello", "world", joiner: "-")
|
||||
</code></pre>
|
||||
<p>在这个例子中,Swift 自动为 <code>joiner</code> 提供了外部参数名。因此,当函数调用时,外部参数名必须使用,这样使得参数的用途变得清晰。</p>
|
||||
<pre><code class="lang-swift">join("hello", "world", joiner: "-")
|
||||
// returns "hello-world"
|
||||
</code></pre><blockquote>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>你可以使用<code>下划线(_)</code>作为默认值参数的外部参数名,这样可以在调用时不用提供外部参数名。但是给带默认值的参数命名总是更加合适的。</p>
|
||||
</blockquote>
|
||||
@ -788,7 +809,7 @@ println("\(total.vowels) vowels and \(total.consonants) consonants")
|
||||
<p>一个<code>可变参数(variadic parameter)</code>可以接受一个或多个值。函数调用时,你可以用可变参数来传入不确定数量的输入参数。通过在变量类型名后面加入<code>(...)</code>的方式来定义可变参数。</p>
|
||||
<p>传入可变参数的值在函数体内当做这个类型的一个数组。例如,一个叫做 <code>numbers</code> 的 <code>Double...</code> 型可变参数,在函数体内可以当做一个叫 <code>numbers</code> 的 <code>Double[]</code> 型的数组常量。</p>
|
||||
<p>下面的这个函数用来计算一组任意长度数字的算术平均数:</p>
|
||||
<pre><code>func arithmeticMean(numbers: Double...) -> Double {
|
||||
<pre><code class="lang-swift">func arithmeticMean(numbers: Double...) -> Double {
|
||||
var total: Double = 0
|
||||
for number in numbers {
|
||||
total += number
|
||||
@ -799,7 +820,8 @@ arithmeticMean(1, 2, 3, 4, 5)
|
||||
// returns 3.0, which is the arithmetic mean of these five numbers
|
||||
arithmeticMean(3, 8, 19)
|
||||
// returns 10.0, which is the arithmetic mean of these three numbers
|
||||
</code></pre><blockquote>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>一个函数至多能有一个可变参数,而且它必须是参数表中最后的一个。这样做是为了避免函数调用时出现歧义。</p>
|
||||
</blockquote>
|
||||
@ -808,7 +830,7 @@ arithmeticMean(3, 8, 19)
|
||||
<p>函数参数默认是常量。试图在函数体中更改参数值将会导致编译错误。这意味着你不能错误地更改参数值。</p>
|
||||
<p>但是,有时候,如果函数中有传入参数的变量值副本将是很有用的。你可以通过指定一个或多个参数为变量参数,从而避免自己在函数中定义新的变量。变量参数不是常量,你可以在函数中把它当做新的可修改副本来使用。</p>
|
||||
<p>通过在参数名前加关键字 <code>var</code> 来定义变量参数:</p>
|
||||
<pre><code>func alignRight(var string: String, count: Int, pad: Character) -> String {
|
||||
<pre><code class="lang-swift">func alignRight(var string: String, count: Int, pad: Character) -> String {
|
||||
let amountToPad = count - countElements(string)
|
||||
for _ in 1...amountToPad {
|
||||
string = pad + string
|
||||
@ -819,7 +841,8 @@ let originalString = "hello"
|
||||
let paddedString = alignRight(originalString, 10, "-")
|
||||
// paddedString is equal to "-----hello"
|
||||
// originalString is still equal to "hello"
|
||||
</code></pre><p>这个例子中定义了一个新的叫做 <code>alignRight</code> 的函数,用来右对齐输入的字符串到一个长的输出字符串中。左侧空余的地方用指定的填充字符填充。这个例子中,字符串<code>"hello"</code>被转换成了<code>"-----hello"</code>。</p>
|
||||
</code></pre>
|
||||
<p>这个例子中定义了一个新的叫做 <code>alignRight</code> 的函数,用来右对齐输入的字符串到一个长的输出字符串中。左侧空余的地方用指定的填充字符填充。这个例子中,字符串<code>"hello"</code>被转换成了<code>"-----hello"</code>。</p>
|
||||
<p><code>alignRight</code> 函数将参数 <code>string</code> 定义为变量参数。这意味着 <code>string</code> 现在可以作为一个局部变量,用传入的字符串值初始化,并且可以在函数体中进行操作。</p>
|
||||
<p>该函数首先计算出多少个字符需要被添加到 <code>string</code> 的左边,以右对齐到总的字符串中。这个值存在局部常量 <code>amountToPad</code> 中。这个函数然后将 <code>amountToPad</code> 多的填充(pad)字符填充到 <code>string</code> 左边,并返回结果。它使用了 <code>string</code> 这个变量参数来进行所有字符串操作。</p>
|
||||
<blockquote>
|
||||
@ -835,19 +858,21 @@ let paddedString = alignRight(originalString, 10, "-")
|
||||
<p>输入输出参数不能有默认值,而且可变参数不能用 <code>inout</code> 标记。如果你用 <code>inout</code> 标记一个参数,这个参数不能被 <code>var</code> 或者 <code>let</code> 标记。</p>
|
||||
</blockquote>
|
||||
<p>下面是例子,<code>swapTwoInts</code> 函数,有两个分别叫做 <code>a</code> 和 <code>b</code> 的输出输出参数:</p>
|
||||
<pre><code>func swapTwoInts(inout a: Int, inout b: Int) {
|
||||
<pre><code class="lang-swift">func swapTwoInts(inout a: Int, inout b: Int) {
|
||||
let temporaryA = a
|
||||
a = b
|
||||
b = temporaryA
|
||||
}
|
||||
</code></pre><p>这个 <code>swapTwoInts</code> 函数仅仅交换 <code>a</code> 与 <code>b</code> 的值。该函数先将 <code>a</code> 的值存到一个暂时常量 <code>temporaryA</code> 中,然后将 <code>b</code> 的值赋给 <code>a</code>,最后将 <code>temporaryA</code> 幅值给 <code>b</code>。</p>
|
||||
</code></pre>
|
||||
<p>这个 <code>swapTwoInts</code> 函数仅仅交换 <code>a</code> 与 <code>b</code> 的值。该函数先将 <code>a</code> 的值存到一个暂时常量 <code>temporaryA</code> 中,然后将 <code>b</code> 的值赋给 <code>a</code>,最后将 <code>temporaryA</code> 幅值给 <code>b</code>。</p>
|
||||
<p>你可以用两个 <code>Int</code> 型的变量来调用 <code>swapTwoInts</code>。需要注意的是,<code>someInt</code> 和 <code>anotherInt</code> 在传入 <code>swapTwoInts</code> 函数前,都加了 <code>&</code> 的前缀:</p>
|
||||
<pre><code>var someInt = 3
|
||||
<pre><code class="lang-swift">var someInt = 3
|
||||
var anotherInt = 107
|
||||
swapTwoInts(&someInt, &anotherInt)
|
||||
println("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
|
||||
// prints "someInt is now 107, and anotherInt is now 3”
|
||||
</code></pre><p>从上面这个例子中,我们可以看到 <code>someInt</code> 和 <code>anotherInt</code> 的原始值在 <code>swapTwoInts</code> 函数中被修改,尽管它们的定义在函数体外。</p>
|
||||
</code></pre>
|
||||
<p>从上面这个例子中,我们可以看到 <code>someInt</code> 和 <code>anotherInt</code> 的原始值在 <code>swapTwoInts</code> 函数中被修改,尽管它们的定义在函数体外。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>输出输出参数和返回值是不一样的。上面的 <code>swapTwoInts</code> 函数并没有定义任何返回值,但仍然修改了 <code>someInt</code> 和 <code>anotherInt</code> 的值。输入输出参数是函数对函数体外产生影响的另一种方式。
|
||||
@ -856,66 +881,76 @@ println("someInt is now \(someInt), and anotherInt is now \(anotherInt)&quo
|
||||
</blockquote>
|
||||
<p>每个函数都有种特定的函数类型,由函数的参数类型和返回类型组成。</p>
|
||||
<p>例如:</p>
|
||||
<pre><code>func addTwoInts(a: Int, b: Int) -> Int {
|
||||
<pre><code class="lang-swift">func addTwoInts(a: Int, b: Int) -> Int {
|
||||
return a + b
|
||||
}
|
||||
func multiplyTwoInts(a: Int, b: Int) -> Int {
|
||||
return a * b
|
||||
}
|
||||
</code></pre><p>这个例子中定义了两个简单的数学函数:<code>addTwoInts</code> 和 <code>multiplyTwoInts</code>。这两个函数都传入两个 <code>Int</code> 类型, 返回一个合适的<code>Int</code>值。</p>
|
||||
</code></pre>
|
||||
<p>这个例子中定义了两个简单的数学函数:<code>addTwoInts</code> 和 <code>multiplyTwoInts</code>。这两个函数都传入两个 <code>Int</code> 类型, 返回一个合适的<code>Int</code>值。</p>
|
||||
<p>这两个函数的类型是 <code>(Int, Int) -> Int</code>,可以读作“这个函数类型,它有两个 <code>Int</code> 型的参数并返回一个 <code>Int</code> 型的值。”。</p>
|
||||
<p>下面是另一个例子,一个没有参数,也没有返回值的函数:</p>
|
||||
<pre><code>func printHelloWorld() {
|
||||
<pre><code class="lang-swift">func printHelloWorld() {
|
||||
println("hello, world")
|
||||
}
|
||||
</code></pre><p>这个函数的类型是:<code>() -> ()</code>,或者叫“没有参数,并返回 <code>Void</code> 类型的函数。”。没有指定返回类型的函数总返回 <code>Void</code>。在Swift中,<code>Void</code> 与空的元组是一样的。</p>
|
||||
</code></pre>
|
||||
<p>这个函数的类型是:<code>() -> ()</code>,或者叫“没有参数,并返回 <code>Void</code> 类型的函数。”。没有指定返回类型的函数总返回 <code>Void</code>。在Swift中,<code>Void</code> 与空的元组是一样的。</p>
|
||||
<h3 id="-using-function-types-">使用函数类型(Using Function Types)</h3>
|
||||
<p>在Swift中,使用函数类型就像使用其他类型一样。例如,你可以定义一个类型为函数的常量或变量,并将函数赋值给它:</p>
|
||||
<pre><code>var mathFunction: (Int, Int) -> Int = addTwoInts
|
||||
</code></pre><p>这个可以读作:</p>
|
||||
<pre><code class="lang-swift">var mathFunction: (Int, Int) -> Int = addTwoInts
|
||||
</code></pre>
|
||||
<p>这个可以读作:</p>
|
||||
<p>“定义一个叫做 <code>mathFunction</code> 的变量,类型是‘一个有两个 <code>Int</code> 型的参数并返回一个 <code>Int</code> 型的值的函数’,并让这个新变量指向 <code>addTwoInts</code> 函数”。</p>
|
||||
<p><code>addTwoInts</code> 和 <code>mathFunction</code> 有同样的类型,所以这个赋值过程在 Swift 类型检查中是允许的。</p>
|
||||
<p>现在,你可以用 <code>mathFunction</code> 来调用被赋值的函数了:</p>
|
||||
<pre><code>println("Result: \(mathFunction(2, 3))")
|
||||
<pre><code class="lang-swift">println("Result: \(mathFunction(2, 3))")
|
||||
// prints "Result: 5
|
||||
</code></pre><p>有相同匹配类型的不同函数可以被赋值给同一个变量,就像非函数类型的变量一样:</p>
|
||||
<pre><code>mathFunction = multiplyTwoInts
|
||||
</code></pre>
|
||||
<p>有相同匹配类型的不同函数可以被赋值给同一个变量,就像非函数类型的变量一样:</p>
|
||||
<pre><code class="lang-swift">mathFunction = multiplyTwoInts
|
||||
println("Result: \(mathFunction(2, 3))")
|
||||
// prints "Result: 6"
|
||||
</code></pre><p>就像其他类型一样,当赋值一个函数给常量或变量时,你可以让 Swift 来推测其函数类型:</p>
|
||||
<pre><code>let anotherMathFunction = addTwoInts
|
||||
</code></pre>
|
||||
<p>就像其他类型一样,当赋值一个函数给常量或变量时,你可以让 Swift 来推测其函数类型:</p>
|
||||
<pre><code class="lang-swift">let anotherMathFunction = addTwoInts
|
||||
// anotherMathFunction is inferred to be of type (Int, Int) -> Int
|
||||
</code></pre><h3 id="-function-types-as-parameter-types-">函数类型作为参数类型(Function Types as Parameter Types)</h3>
|
||||
</code></pre>
|
||||
<h3 id="-function-types-as-parameter-types-">函数类型作为参数类型(Function Types as Parameter Types)</h3>
|
||||
<p>你可以用<code>(Int, Int) -> Int</code>这样的函数类型作为另一个函数的参数类型。这样你可以将函数的一部分实现交由给函数的调用者。</p>
|
||||
<p>下面是另一个例子,正如上面的函数一样,同样是输出某种数学运算结果:</p>
|
||||
<pre><code>func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) {
|
||||
<pre><code class="lang-swift">func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) {
|
||||
println("Result: \(mathFunction(a, b))")
|
||||
}
|
||||
printMathResult(addTwoInts, 3, 5)
|
||||
// prints "Result: 8”
|
||||
</code></pre><p>这个例子定义了 <code>printMathResult</code> 函数,它有三个参数:第一个参数叫 <code>mathFunction</code>,类型是<code>(Int, Int) -> Int</code>,你可以传入任何这种类型的函数;第二个和第三个参数叫 <code>a</code> 和 <code>b</code>,它们的类型都是 <code>Int</code>,这两个值作为已给的函数的输入值。</p>
|
||||
</code></pre>
|
||||
<p>这个例子定义了 <code>printMathResult</code> 函数,它有三个参数:第一个参数叫 <code>mathFunction</code>,类型是<code>(Int, Int) -> Int</code>,你可以传入任何这种类型的函数;第二个和第三个参数叫 <code>a</code> 和 <code>b</code>,它们的类型都是 <code>Int</code>,这两个值作为已给的函数的输入值。</p>
|
||||
<p>当 <code>printMathResult</code> 被调用时,它被传入 <code>addTwoInts</code> 函数和整数<code>3</code>和<code>5</code>。它用传入<code>3</code>和<code>5</code>调用 <code>addTwoInts</code>,并输出结果:<code>8</code>。</p>
|
||||
<p><code>printMathResult</code> 函数的作用就是输出另一个合适类型的数学函数的调用结果。它不关心传入函数是如何实现的,它只关心这个传入的函数类型是正确的。这使得 <code>printMathResult</code> 可以以一种类型安全(type-safe)的方式来保证传入函数的调用是正确的。</p>
|
||||
<h3 id="-function-type-as-return-types-">函数类型作为返回类型(Function Type as Return Types)</h3>
|
||||
<p>你可以用函数类型作为另一个函数的返回类型。你需要做的是在返回箭头(<code>-></code>)后写一个完整的函数类型。</p>
|
||||
<p>下面的这个例子中定义了两个简单函数,分别是 <code>stepForward</code> 和<code>stepBackward</code>。<code>stepForward</code> 函数返回一个比输入值大一的值。<code>stepBackward</code> 函数返回一个比输入值小一的值。这两个函数的类型都是 <code>(Int) -> Int</code>:</p>
|
||||
<pre><code>func stepForward(input: Int) -> Int {
|
||||
<pre><code class="lang-swift">func stepForward(input: Int) -> Int {
|
||||
return input + 1
|
||||
}
|
||||
func stepBackward(input: Int) -> Int {
|
||||
return input - 1
|
||||
}
|
||||
</code></pre><p>下面这个叫做 <code>chooseStepFunction</code> 的函数,它的返回类型是 <code>(Int) -> Int</code> 的函数。<code>chooseStepFunction</code> 根据布尔值 <code>backwards</code> 来返回 <code>stepForward</code> 函数或 <code>stepBackward</code> 函数:</p>
|
||||
<pre><code>func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
|
||||
</code></pre>
|
||||
<p>下面这个叫做 <code>chooseStepFunction</code> 的函数,它的返回类型是 <code>(Int) -> Int</code> 的函数。<code>chooseStepFunction</code> 根据布尔值 <code>backwards</code> 来返回 <code>stepForward</code> 函数或 <code>stepBackward</code> 函数:</p>
|
||||
<pre><code class="lang-swift">func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
|
||||
return backwards ? stepBackward : stepForward
|
||||
}
|
||||
</code></pre><p>你现在可以用 <code>chooseStepFunction</code> 来获得一个函数,不管是那个方向:</p>
|
||||
<pre><code>var currentValue = 3
|
||||
</code></pre>
|
||||
<p>你现在可以用 <code>chooseStepFunction</code> 来获得一个函数,不管是那个方向:</p>
|
||||
<pre><code class="lang-swift">var currentValue = 3
|
||||
let moveNearerToZero = chooseStepFunction(currentValue > 0)
|
||||
// moveNearerToZero now refers to the stepBackward() function
|
||||
</code></pre><p>上面这个例子中计算出从 <code>currentValue</code> 逐渐接近到<code>0</code>是需要向正数走还是向负数走。<code>currentValue</code> 的初始值是<code>3</code>,这意味着 <code>currentValue > 0</code> 是真的(<code>true</code>),这将使得 <code>chooseStepFunction</code> 返回 <code>stepBackward</code> 函数。一个指向返回的函数的引用保存在了 <code>moveNearerToZero</code> 常量中。</p>
|
||||
</code></pre>
|
||||
<p>上面这个例子中计算出从 <code>currentValue</code> 逐渐接近到<code>0</code>是需要向正数走还是向负数走。<code>currentValue</code> 的初始值是<code>3</code>,这意味着 <code>currentValue > 0</code> 是真的(<code>true</code>),这将使得 <code>chooseStepFunction</code> 返回 <code>stepBackward</code> 函数。一个指向返回的函数的引用保存在了 <code>moveNearerToZero</code> 常量中。</p>
|
||||
<p>现在,<code>moveNearerToZero</code> 指向了正确的函数,它可以被用来数到<code>0</code>:</p>
|
||||
<pre><code>println("Counting to zero:")
|
||||
<pre><code class="lang-swift">println("Counting to zero:")
|
||||
// Counting to zero:
|
||||
while currentValue != 0 {
|
||||
println("\(currentValue)... ")
|
||||
@ -926,12 +961,13 @@ println("zero!")
|
||||
// 2...
|
||||
// 1...
|
||||
// zero!
|
||||
</code></pre><p><a name="Nested_Functions"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="Nested_Functions"></a></p>
|
||||
<h2 id="-nested-functions-">嵌套函数(Nested Functions)</h2>
|
||||
<p>这章中你所见到的所有函数都叫全局函数(global functions),它们定义在全局域中。你也可以把函数定义在别的函数体中,称作嵌套函数(nested functions)。</p>
|
||||
<p>默认情况下,嵌套函数是对外界不可见的,但是可以被他们封闭函数(enclosing function)来调用。一个封闭函数也可以返回它的某一个嵌套函数,使得这个函数可以在其他域中被使用。</p>
|
||||
<p>你可以用返回嵌套函数的方式重写 <code>chooseStepFunction</code> 函数:</p>
|
||||
<pre><code>func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
|
||||
<pre><code class="lang-swift">func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
|
||||
func stepForward(input: Int) -> Int { return input + 1 }
|
||||
func stepBackward(input: Int) -> Int { return input - 1 }
|
||||
return backwards ? stepBackward : stepForward
|
||||
@ -950,6 +986,7 @@ println("zero!")
|
||||
// -1...
|
||||
// zero!
|
||||
</code></pre>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.7" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.7" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.8" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.8" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.9" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.9" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.10" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.10" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.11" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.11" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.12" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.12" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.13" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.13" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.14" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.14" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.15" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.15" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.16" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.16" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.17" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.17" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.18" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.18" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.19" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.19" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.20" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.20" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.21" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.21" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.22" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.22" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.23" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.23" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
@ -615,32 +615,36 @@
|
||||
<p>按位取反运算符<code>~</code>对一个操作数的每一位都取反。</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitwiseNOT_2x.png" alt="Art/bitwiseNOT_2x.png" title="Art/bitwiseNOT_2x.png"></p>
|
||||
<p>这个运算符是前置的,所以请不加任何空格地写着操作数之前。</p>
|
||||
<pre><code>let initialBits: UInt8 = 0b00001111
|
||||
<pre><code class="lang-swift">let initialBits: UInt8 = 0b00001111
|
||||
let invertedBits = ~initialBits // 等于 0b11110000
|
||||
</code></pre><p><code>UInt8</code>是8位无符整型,可以存储0~255之间的任意数。这个例子初始化一个整型为二进制值<code>00001111</code>(前4位为<code>0</code>,后4位为<code>1</code>),它的十进制值为<code>15</code>。</p>
|
||||
</code></pre>
|
||||
<p><code>UInt8</code>是8位无符整型,可以存储0~255之间的任意数。这个例子初始化一个整型为二进制值<code>00001111</code>(前4位为<code>0</code>,后4位为<code>1</code>),它的十进制值为<code>15</code>。</p>
|
||||
<p>使用按位取反运算<code>~</code>对<code>initialBits</code>操作,然后赋值给<code>invertedBits</code>这个新常量。这个新常量的值等于所有位都取反的<code>initialBits</code>,即<code>1</code>变成<code>0</code>,<code>0</code>变成<code>1</code>,变成了<code>11110000</code>,十进制值为<code>240</code>。</p>
|
||||
<h3 id="-">按位与运算符</h3>
|
||||
<p>按位与运算符对两个数进行操作,然后返回一个新的数,这个数的每个位都需要两个输入数的同一位都为1时才为1。</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitwiseAND_2x.png" alt="Art/bitwiseAND_2x.png" title="Art/bitwiseAND_2x.png"></p>
|
||||
<p>以下代码,<code>firstSixBits</code>和<code>lastSixBits</code>中间4个位都为1。对它俩进行按位与运算后,就得到了<code>00111100</code>,即十进制的<code>60</code>。</p>
|
||||
<pre><code>let firstSixBits: UInt8 = 0b11111100
|
||||
<pre><code class="lang-swift">let firstSixBits: UInt8 = 0b11111100
|
||||
let lastSixBits: UInt8 = 0b00111111
|
||||
let middleFourBits = firstSixBits & lastSixBits // 等于 00111100
|
||||
</code></pre><h3 id="-">按位或运算</h3>
|
||||
</code></pre>
|
||||
<h3 id="-">按位或运算</h3>
|
||||
<p>按位或运算符<code>|</code>比较两个数,然后返回一个新的数,这个数的每一位设置1的条件是两个输入数的同一位都不为0(即任意一个为1,或都为1)。</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitwiseOR_2x.png" alt="Art/bitwiseOR_2x.png" title="Art/bitwiseOR_2x.png"></p>
|
||||
<p>如下代码,<code>someBits</code>和<code>moreBits</code>在不同位上有<code>1</code>。按位或运行的结果是<code>11111110</code>,即十进制的<code>254</code>。</p>
|
||||
<pre><code>let someBits: UInt8 = 0b10110010
|
||||
<pre><code class="lang-swift">let someBits: UInt8 = 0b10110010
|
||||
let moreBits: UInt8 = 0b01011110
|
||||
let combinedbits = someBits | moreBits // 等于 11111110
|
||||
</code></pre><h3 id="-">按位异或运算符</h3>
|
||||
</code></pre>
|
||||
<h3 id="-">按位异或运算符</h3>
|
||||
<p>按位异或运算符<code>^</code>比较两个数,然后返回一个数,这个数的每个位设为<code>1</code>的条件是两个输入数的同一位不同,如果相同就设为<code>0</code>。</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitwiseXOR_2x.png" alt="Art/bitwiseXOR_2x.png" title="Art/bitwiseXOR_2x.png"></p>
|
||||
<p>以下代码,<code>firstBits</code>和<code>otherBits</code>都有一个<code>1</code>跟另一个数不同的。所以按位异或的结果是把它这些位置为<code>1</code>,其他都置为<code>0</code>。</p>
|
||||
<pre><code>let firstBits: UInt8 = 0b00010100
|
||||
<pre><code class="lang-swift">let firstBits: UInt8 = 0b00010100
|
||||
let otherBits: UInt8 = 0b00000101
|
||||
let outputBits = firstBits ^ otherBits // 等于 00010001
|
||||
</code></pre><h3 id="-">按位左移/右移运算符</h3>
|
||||
</code></pre>
|
||||
<h3 id="-">按位左移/右移运算符</h3>
|
||||
<p>左移运算符<code><<</code>和右移运算符<code>>></code>会把一个数的所有比特位按以下定义的规则向左或向右移动指定位数。</p>
|
||||
<p>按位左移和按位右移的效果相当把一个整数乘于或除于一个因子为<code>2</code>的整数。向左移动一个整型的比特位相当于把这个数乘于<code>2</code>,向右移一位就是除于<code>2</code>。</p>
|
||||
<h4 id="-">无符整型的移位操作</h4>
|
||||
@ -648,18 +652,20 @@ let outputBits = firstBits ^ otherBits // 等于 00010001
|
||||
<p>已经存在的比特位向左或向右移动指定的位数。被移出整型存储边界的的位数直接抛弃,移动留下的空白位用零<code>0</code>来填充。这种方法称为逻辑移位。</p>
|
||||
<p>以下这张把展示了 <code>11111111 << 1</code>(<code>11111111</code>向左移1位),和 <code>11111111 >> 1</code>(<code>11111111</code>向右移1位)。蓝色的是被移位的,灰色是被抛弃的,橙色的<code>0</code>是被填充进来的。</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitshiftUnsigned_2x.png" alt="Art/bitshiftUnsigned_2x.png" title="Art/bitshiftUnsigned_2x.png"></p>
|
||||
<pre><code>let shiftBits: UInt8 = 4 // 即二进制的00000100
|
||||
<pre><code class="lang-swift">let shiftBits: UInt8 = 4 // 即二进制的00000100
|
||||
shiftBits << 1 // 00001000
|
||||
shiftBits << 2 // 00010000
|
||||
shiftBits << 5 // 10000000
|
||||
shiftBits << 6 // 00000000
|
||||
shiftBits >> 2 // 00000001
|
||||
</code></pre><p>你可以使用移位操作进行其他数据类型的编码和解码。</p>
|
||||
<pre><code>let pink: UInt32 = 0xCC6699
|
||||
</code></pre>
|
||||
<p>你可以使用移位操作进行其他数据类型的编码和解码。</p>
|
||||
<pre><code class="lang-swift">let pink: UInt32 = 0xCC6699
|
||||
let redComponent = (pink & 0xFF0000) >> 16 // redComponent 是 0xCC, 即 204
|
||||
let greenComponent = (pink & 0x00FF00) >> 8 // greenComponent 是 0x66, 即 102
|
||||
let blueComponent = pink & 0x0000FF // blueComponent 是 0x99, 即 153
|
||||
</code></pre><p>这个例子使用了一个<code>UInt32</code>的命名为<code>pink</code>的常量来存储层叠样式表<code>CSS</code>中粉色的颜色值,<code>CSS</code>颜色<code>#CC6699</code>在Swift用十六进制<code>0xCC6699</code>来表示。然后使用按位与(&)和按位右移就可以从这个颜色值中解析出红(CC),绿(66),蓝(99)三个部分。</p>
|
||||
</code></pre>
|
||||
<p>这个例子使用了一个<code>UInt32</code>的命名为<code>pink</code>的常量来存储层叠样式表<code>CSS</code>中粉色的颜色值,<code>CSS</code>颜色<code>#CC6699</code>在Swift用十六进制<code>0xCC6699</code>来表示。然后使用按位与(&)和按位右移就可以从这个颜色值中解析出红(CC),绿(66),蓝(99)三个部分。</p>
|
||||
<p>对<code>0xCC6699</code>和<code>0xFF0000</code>进行按位与<code>&</code>操作就可以得到红色部分。<code>0xFF0000</code>中的<code>0</code>了遮盖了<code>OxCC6699</code>的第二和第三个字节,这样<code>6699</code>被忽略了,只留下<code>0xCC0000</code>。</p>
|
||||
<p>然后,按向右移动16位,即 <code>>> 16</code>。十六进制中每两个字符是8比特位,所以移动16位的结果是把<code>0xCC0000</code>变成<code>0x0000CC</code>。这和<code>0xCC</code>是相等的,都是十进制的<code>204</code>。</p>
|
||||
<p>同样的,绿色部分来自于<code>0xCC6699</code>和<code>0x00FF00</code>的按位操作得到<code>0x006600</code>。然后向右移动8們,得到<code>0x66</code>,即十进制的<code>102</code>。</p>
|
||||
@ -687,11 +693,12 @@ let blueComponent = pink & 0x0000FF // blueComponent 是 0x99, 即
|
||||
<h2 id="-">溢出运算符</h2>
|
||||
<p>默认情况下,当你往一个整型常量或变量赋于一个它不能承载的大数时,Swift不会让你这么干的,它会报错。这样,在操作过大或过小的数的时候就很安全了。</p>
|
||||
<p>例如,<code>Int16</code>整型能承载的整数范围是<code>-32768</code>到<code>32767</code>,如果给它赋上超过这个范围的数,就会报错:</p>
|
||||
<pre><code>var potentialOverflow = Int16.max
|
||||
<pre><code class="lang-swift">var potentialOverflow = Int16.max
|
||||
// potentialOverflow 等于 32767, 这是 Int16 能承载的最大整数
|
||||
potentialOverflow += 1
|
||||
// 噢, 出错了
|
||||
</code></pre><p>对过大或过小的数值进行错误处理让你的数值边界条件更灵活。</p>
|
||||
</code></pre>
|
||||
<p>对过大或过小的数值进行错误处理让你的数值边界条件更灵活。</p>
|
||||
<p>当然,你有意在溢出时对有效位进行截断,你可采用溢出运算,而非错误处理。Swfit为整型计算提供了5个<code>&</code>符号开头的溢出运算符。</p>
|
||||
<ul>
|
||||
<li>溢出加法 <code>&+</code></li>
|
||||
@ -702,44 +709,50 @@ potentialOverflow += 1
|
||||
</ul>
|
||||
<h3 id="-">值的上溢出</h3>
|
||||
<p>下面例子使用了溢出加法<code>&+</code>来解剖的无符整数的上溢出</p>
|
||||
<pre><code>var willOverflow = UInt8.max
|
||||
<pre><code class="lang-swift">var willOverflow = UInt8.max
|
||||
// willOverflow 等于UInt8的最大整数 255
|
||||
willOverflow = willOverflow &+ 1
|
||||
// 这时候 willOverflow 等于 0
|
||||
</code></pre><p><code>willOverflow</code>用<code>Int8</code>所能承载的最大值<code>255</code>(二进制<code>11111111</code>),然后用<code>&+</code>加1。然后<code>UInt8</code>就无法表达这个新值的二进制了,也就导致了这个新值上溢出了,大家可以看下图。溢出后,新值在<code>UInt8</code>的承载范围内的那部分是<code>00000000</code>,也就是<code>0</code>。</p>
|
||||
</code></pre>
|
||||
<p><code>willOverflow</code>用<code>Int8</code>所能承载的最大值<code>255</code>(二进制<code>11111111</code>),然后用<code>&+</code>加1。然后<code>UInt8</code>就无法表达这个新值的二进制了,也就导致了这个新值上溢出了,大家可以看下图。溢出后,新值在<code>UInt8</code>的承载范围内的那部分是<code>00000000</code>,也就是<code>0</code>。</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/overflowAddition_2x.png" alt="Art/overflowAddition_2x.png" title="Art/overflowAddition_2x.png"></p>
|
||||
<h3 id="-">值的下溢出</h3>
|
||||
<p>数值也有可能因为太小而越界。举个例子:</p>
|
||||
<p><code>UInt8</code>的最小值是<code>0</code>(二进制为<code>00000000</code>)。使用<code>&-</code>进行溢出减1,就会得到二进制的<code>11111111</code>即十进制的<code>255</code>。</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/overflowUnsignedSubtraction_2x.png" alt="Art/overflowUnsignedSubtraction_2x.png" title="Art/overflowUnsignedSubtraction_2x.png"></p>
|
||||
<p>Swift代码是这样的:</p>
|
||||
<pre><code>var willUnderflow = UInt8.min
|
||||
<pre><code class="lang-swift">var willUnderflow = UInt8.min
|
||||
// willUnderflow 等于UInt8的最小值0
|
||||
willUnderflow = willUnderflow &- 1
|
||||
// 此时 willUnderflow 等于 255
|
||||
</code></pre><p>有符整型也有类似的下溢出,有符整型所有的减法也都是对包括在符号位在内的二进制数进行二进制减法的,这在 "按位左移/右移运算符" 一节提到过。最小的有符整数是<code>-128</code>,即二进制的<code>10000000</code>。用溢出减法减去去1后,变成了<code>01111111</code>,即UInt8所能承载的最大整数<code>127</code>。</p>
|
||||
</code></pre>
|
||||
<p>有符整型也有类似的下溢出,有符整型所有的减法也都是对包括在符号位在内的二进制数进行二进制减法的,这在 "按位左移/右移运算符" 一节提到过。最小的有符整数是<code>-128</code>,即二进制的<code>10000000</code>。用溢出减法减去去1后,变成了<code>01111111</code>,即UInt8所能承载的最大整数<code>127</code>。</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/overflowSignedSubtraction_2x.png" alt="Art/overflowSignedSubtraction_2x.png" title="Art/overflowSignedSubtraction_2x.png"></p>
|
||||
<p>来看看Swift代码:</p>
|
||||
<pre><code>var signedUnderflow = Int8.min
|
||||
<pre><code class="lang-swift">var signedUnderflow = Int8.min
|
||||
// signedUnderflow 等于最小的有符整数 -128
|
||||
signedUnderflow = signedUnderflow &- 1
|
||||
// 如今 signedUnderflow 等于 127
|
||||
</code></pre><h3 id="-">除零溢出</h3>
|
||||
</code></pre>
|
||||
<h3 id="-">除零溢出</h3>
|
||||
<p>一个数除于0 <code>i / 0</code>,或者对0求余数 <code>i % 0</code>,就会产生一个错误。</p>
|
||||
<pre><code>let x = 1
|
||||
<pre><code class="lang-swift">let x = 1
|
||||
let y = x / 0
|
||||
</code></pre><p>使用它们对应的可溢出的版本的运算符<code>&/</code>和<code>&%</code>进行除0操作时就会得到<code>0</code>值。</p>
|
||||
<pre><code>let x = 1
|
||||
</code></pre>
|
||||
<p>使用它们对应的可溢出的版本的运算符<code>&/</code>和<code>&%</code>进行除0操作时就会得到<code>0</code>值。</p>
|
||||
<pre><code class="lang-swift">let x = 1
|
||||
let y = x &/ 0
|
||||
// y 等于 0
|
||||
</code></pre><p><a name="precedence_and_associativity"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="precedence_and_associativity"></a></p>
|
||||
<h2 id="-">优先级和结合性</h2>
|
||||
<p>运算符的优先级使得一些运算符优先于其他运算符,高优先级的运算符会先被计算。</p>
|
||||
<p>结合性定义相同优先级的运算符在一起时是怎么组合或关联的,是和左边的一组呢,还是和右边的一组。意思就是,到底是和左边的表达式结合呢,还是和右边的表达式结合?</p>
|
||||
<p>在混合表达式中,运算符的优先级和结合性是非常重要的。举个例子,为什么下列表达式的结果为<code>4</code>?</p>
|
||||
<pre><code>2 + 3 * 4 % 5
|
||||
<pre><code class="lang-swift">2 + 3 * 4 % 5
|
||||
// 结果是 4
|
||||
</code></pre><p>如果严格地从左计算到右,计算过程会是这样:</p>
|
||||
</code></pre>
|
||||
<p>如果严格地从左计算到右,计算过程会是这样:</p>
|
||||
<ul>
|
||||
<li>2 plus 3 equals 5;</li>
|
||||
<li>2 + 3 = 5</li>
|
||||
@ -750,14 +763,17 @@ let y = x &/ 0
|
||||
</ul>
|
||||
<p>但是正确答案是<code>4</code>而不是<code>0</code>。优先级高的运算符要先计算,在Swift和C语言中,都是先乘除后加减的。所以,执行完乘法和求余运算才能执行加减运算。</p>
|
||||
<p>乘法和求余拥有相同的优先级,在运算过程中,我们还需要结合性,乘法和求余运算都是左结合的。这相当于在表达式中有隐藏的括号让运算从左开始。</p>
|
||||
<pre><code>2 + ((3 * 4) % 5)
|
||||
</code></pre><p>(3 <em> 4) is 12, so this is equivalent to:
|
||||
<pre><code class="lang-swift">2 + ((3 * 4) % 5)
|
||||
</code></pre>
|
||||
<p>(3 <em> 4) is 12, so this is equivalent to:
|
||||
3 </em> 4 = 12,所以这相当于:</p>
|
||||
<pre><code>2 + (12 % 5)
|
||||
</code></pre><p>(12 % 5) is 2, so this is equivalent to:
|
||||
<pre><code class="lang-swift">2 + (12 % 5)
|
||||
</code></pre>
|
||||
<p>(12 % 5) is 2, so this is equivalent to:
|
||||
12 % 5 = 2,所这又相当于</p>
|
||||
<pre><code>2 + 2
|
||||
</code></pre><p>计算结果为 4。</p>
|
||||
<pre><code class="lang-swift">2 + 2
|
||||
</code></pre>
|
||||
<p>计算结果为 4。</p>
|
||||
<p>查阅Swift运算符的优先级和结合性的完整列表,请看<a href="../chapter3/04_Expressions.html">表达式</a>。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
@ -768,96 +784,109 @@ let y = x &/ 0
|
||||
<p>让已有的运算符也可以对自定义的类和结构进行运算,这称为运算符重载。</p>
|
||||
<p>这个例子展示了如何用<code>+</code>让一个自定义的结构做加法。算术运算符<code>+</code>是一个两目运算符,因为它有两个操作数,而且它必须出现在两个操作数之间。</p>
|
||||
<p>例子中定义了一个名为<code>Vector2D</code>的二维坐标向量 <code>(x,y)</code> 的结构,然后定义了让两个<code>Vector2D</code>的对象相加的运算符函数。</p>
|
||||
<pre><code>struct Vector2D {
|
||||
<pre><code class="lang-swift">struct Vector2D {
|
||||
var x = 0.0, y = 0.0
|
||||
}
|
||||
@infix func + (left: Vector2D, right: Vector2D) -> Vector2D {
|
||||
return Vector2D(x: left.x + right.x, y: left.y + right.y)
|
||||
}
|
||||
</code></pre><p>该运算符函数定义了一个全局的<code>+</code>函数,这个函数需要两个<code>Vector2D</code>类型的参数,返回值也是<code>Vector2D</code>类型。需要定义和实现一个中置运算的时候,在关键字<code>func</code>之前写上属性 <code>@infix</code> 就可以了。</p>
|
||||
</code></pre>
|
||||
<p>该运算符函数定义了一个全局的<code>+</code>函数,这个函数需要两个<code>Vector2D</code>类型的参数,返回值也是<code>Vector2D</code>类型。需要定义和实现一个中置运算的时候,在关键字<code>func</code>之前写上属性 <code>@infix</code> 就可以了。</p>
|
||||
<p>在这个代码实现中,参数被命名为了<code>left</code>和<code>right</code>,代表<code>+</code>左边和右边的两个<code>Vector2D</code>对象。函数返回了一个新的<code>Vector2D</code>的对象,这个对象的<code>x</code>和<code>y</code>分别等于两个参数对象的<code>x</code>和<code>y</code>的和。</p>
|
||||
<p>这个函数是全局的,而不是<code>Vector2D</code>结构的成员方法,所以任意两个<code>Vector2D</code>对象都可以使用这个中置运算符。</p>
|
||||
<pre><code>let vector = Vector2D(x: 3.0, y: 1.0)
|
||||
<pre><code class="lang-swift">let vector = Vector2D(x: 3.0, y: 1.0)
|
||||
let anotherVector = Vector2D(x: 2.0, y: 4.0)
|
||||
let combinedVector = vector + anotherVector
|
||||
// combinedVector 是一个新的Vector2D, 值为 (5.0, 5.0)
|
||||
</code></pre><p>这个例子实现两个向量 <code>(3.0,1.0)</code> 和 <code>(2.0,4.0)</code> 相加,得到向量 <code>(5.0,5.0)</code> 的过程。如下图示:</p>
|
||||
</code></pre>
|
||||
<p>这个例子实现两个向量 <code>(3.0,1.0)</code> 和 <code>(2.0,4.0)</code> 相加,得到向量 <code>(5.0,5.0)</code> 的过程。如下图示:</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/vectorAddition_2x.png" alt="Art/vectorAddition_2x.png" title="Art/vectorAddition_2x.png"></p>
|
||||
<h3 id="-">前置和后置运算符</h3>
|
||||
<p>上个例子演示了一个双目中置运算符的自定义实现,同样我们也可以玩标准单目运算符的实现。单目运算符只有一个操作数,在操作数之前就是前置的,如<code>-a</code>; 在操作数之后就是后置的,如<code>i++</code>。</p>
|
||||
<p>实现一个前置或后置运算符时,在定义该运算符的时候于关键字<code>func</code>之前标注 <code>@prefix</code> 或 <code>@postfix</code> 属性。</p>
|
||||
<pre><code>@prefix func - (vector: Vector2D) -> Vector2D {
|
||||
<pre><code class="lang-swift">@prefix func - (vector: Vector2D) -> Vector2D {
|
||||
return Vector2D(x: -vector.x, y: -vector.y)
|
||||
}
|
||||
</code></pre><p>这段代码为<code>Vector2D</code>类型提供了单目减运算<code>-a</code>,<code>@prefix</code>属性表明这是个前置运算符。</p>
|
||||
</code></pre>
|
||||
<p>这段代码为<code>Vector2D</code>类型提供了单目减运算<code>-a</code>,<code>@prefix</code>属性表明这是个前置运算符。</p>
|
||||
<p>对于数值,单目减运算符可以把正数变负数,把负数变正数。对于<code>Vector2D</code>,单目减运算将其<code>x</code>和<code>y</code>都进进行单目减运算。</p>
|
||||
<pre><code>let positive = Vector2D(x: 3.0, y: 4.0)
|
||||
<pre><code class="lang-swift">let positive = Vector2D(x: 3.0, y: 4.0)
|
||||
let negative = -positive
|
||||
// negative 为 (-3.0, -4.0)
|
||||
let alsoPositive = -negative
|
||||
// alsoPositive 为 (3.0, 4.0)
|
||||
</code></pre><h3 id="-">组合赋值运算符</h3>
|
||||
</code></pre>
|
||||
<h3 id="-">组合赋值运算符</h3>
|
||||
<p>组合赋值是其他运算符和赋值运算符一起执行的运算。如<code>+=</code>把加运算和赋值运算组合成一个操作。实现一个组合赋值符号需要使用<code>@assignment</code>属性,还需要把运算符的左参数设置成<code>inout</code>,因为这个参数会在运算符函数内直接修改它的值。</p>
|
||||
<pre><code>@assignment func += (inout left: Vector2D, right: Vector2D) {
|
||||
<pre><code class="lang-swift">@assignment func += (inout left: Vector2D, right: Vector2D) {
|
||||
left = left + right
|
||||
}
|
||||
</code></pre><p>因为加法运算在之前定义过了,这里无需重新定义。所以,加赋运算符函数使用已经存在的高级加法运算符函数来执行左值加右值的运算。</p>
|
||||
<pre><code>var original = Vector2D(x: 1.0, y: 2.0)
|
||||
</code></pre>
|
||||
<p>因为加法运算在之前定义过了,这里无需重新定义。所以,加赋运算符函数使用已经存在的高级加法运算符函数来执行左值加右值的运算。</p>
|
||||
<pre><code class="lang-swift">var original = Vector2D(x: 1.0, y: 2.0)
|
||||
let vectorToAdd = Vector2D(x: 3.0, y: 4.0)
|
||||
original += vectorToAdd
|
||||
// original 现在为 (4.0, 6.0)
|
||||
</code></pre><p>你可以将 <code>@assignment</code> 属性和 <code>@prefix</code> 或 <code>@postfix</code> 属性起来组合,实现一个<code>Vector2D</code>的前置运算符。</p>
|
||||
<pre><code>@prefix @assignment func ++ (inout vector: Vector2D) -> Vector2D {
|
||||
</code></pre>
|
||||
<p>你可以将 <code>@assignment</code> 属性和 <code>@prefix</code> 或 <code>@postfix</code> 属性起来组合,实现一个<code>Vector2D</code>的前置运算符。</p>
|
||||
<pre><code class="lang-swift">@prefix @assignment func ++ (inout vector: Vector2D) -> Vector2D {
|
||||
vector += Vector2D(x: 1.0, y: 1.0)
|
||||
return vector
|
||||
}
|
||||
</code></pre><p>这个前置使用了已经定义好的高级加赋运算,将自己加上一个值为 <code>(1.0,1.0)</code> 的对象然后赋给自己,然后再将自己返回。</p>
|
||||
<pre><code>var toIncrement = Vector2D(x: 3.0, y: 4.0)
|
||||
</code></pre>
|
||||
<p>这个前置使用了已经定义好的高级加赋运算,将自己加上一个值为 <code>(1.0,1.0)</code> 的对象然后赋给自己,然后再将自己返回。</p>
|
||||
<pre><code class="lang-swift">var toIncrement = Vector2D(x: 3.0, y: 4.0)
|
||||
let afterIncrement = ++toIncrement
|
||||
// toIncrement 现在是 (4.0, 5.0)
|
||||
// afterIncrement 现在也是 (4.0, 5.0)
|
||||
</code></pre><blockquote>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>默认的赋值符是不可重载的。只有组合赋值符可以重载。三目条件运算符 <code>a?b:c</code> 也是不可重载。</p>
|
||||
</blockquote>
|
||||
<h3 id="-">比较运算符</h3>
|
||||
<p>Swift无所知道自定义类型是否相等或不等,因为等于或者不等于由你的代码说了算了。所以自定义的类和结构要使用比较符<code>==</code>或<code>!=</code>就需要重载。</p>
|
||||
<p>定义相等运算符函数跟定义其他中置运算符雷同:</p>
|
||||
<pre><code>@infix func == (left: Vector2D, right: Vector2D) -> Bool {
|
||||
<pre><code class="lang-swift">@infix func == (left: Vector2D, right: Vector2D) -> Bool {
|
||||
return (left.x == right.x) && (left.y == right.y)
|
||||
}
|
||||
|
||||
@infix func != (left: Vector2D, right: Vector2D) -> Bool {
|
||||
return !(left == right)
|
||||
}
|
||||
</code></pre><p>上述代码实现了相等运算符<code>==</code>来判断两个<code>Vector2D</code>对象是否有相等的值,相等的概念就是他们有相同的<code>x</code>值和相同的<code>y</code>值,我们就用这个逻辑来实现。接着使用<code>==</code>的结果实现了不相等运算符<code>!=</code>。</p>
|
||||
</code></pre>
|
||||
<p>上述代码实现了相等运算符<code>==</code>来判断两个<code>Vector2D</code>对象是否有相等的值,相等的概念就是他们有相同的<code>x</code>值和相同的<code>y</code>值,我们就用这个逻辑来实现。接着使用<code>==</code>的结果实现了不相等运算符<code>!=</code>。</p>
|
||||
<p>现在我们可以使用这两个运算符来判断两个<code>Vector2D</code>对象是否相等。</p>
|
||||
<pre><code>let twoThree = Vector2D(x: 2.0, y: 3.0)
|
||||
<pre><code class="lang-swift">let twoThree = Vector2D(x: 2.0, y: 3.0)
|
||||
let anotherTwoThree = Vector2D(x: 2.0, y: 3.0)
|
||||
if twoThree == anotherTwoThree {
|
||||
println("这两个向量是相等的.")
|
||||
}
|
||||
// prints "这两个向量是相等的."
|
||||
</code></pre><h3 id="-">自定义运算符</h3>
|
||||
</code></pre>
|
||||
<h3 id="-">自定义运算符</h3>
|
||||
<p>标准的运算符不够玩,那你可以声明一些个性的运算符,但个性的运算符只能使用这些字符 <code>/ = - + * % < >!& | ^。~</code>。</p>
|
||||
<p>新的运算符声明需在全局域使用<code>operator</code>关键字声明,可以声明为前置,中置或后置的。</p>
|
||||
<pre><code>operator prefix +++ {}
|
||||
</code></pre><p>这段代码定义了一个新的前置运算符叫<code>+++</code>,此前Swift并不存在这个运算符。此处为了演示,我们让<code>+++</code>对<code>Vector2D</code>对象的操作定义为 <code>双自增</code> 这样一个独有的操作,这个操作使用了之前定义的加赋运算实现了自已加上自己然后返回的运算。</p>
|
||||
<pre><code>@prefix @assignment func +++ (inout vector: Vector2D) -> Vector2D {
|
||||
<pre><code class="lang-swift">operator prefix +++ {}
|
||||
</code></pre>
|
||||
<p>这段代码定义了一个新的前置运算符叫<code>+++</code>,此前Swift并不存在这个运算符。此处为了演示,我们让<code>+++</code>对<code>Vector2D</code>对象的操作定义为 <code>双自增</code> 这样一个独有的操作,这个操作使用了之前定义的加赋运算实现了自已加上自己然后返回的运算。</p>
|
||||
<pre><code class="lang-swift">@prefix @assignment func +++ (inout vector: Vector2D) -> Vector2D {
|
||||
vector += vector
|
||||
return vector
|
||||
}
|
||||
</code></pre><p><code>Vector2D</code> 的 <code>+++</code> 的实现和 <code>++</code> 的实现很接近, 唯一不同的前者是加自己, 后者是加值为 <code>(1.0, 1.0)</code> 的向量.</p>
|
||||
<pre><code>var toBeDoubled = Vector2D(x: 1.0, y: 4.0)
|
||||
</code></pre>
|
||||
<p><code>Vector2D</code> 的 <code>+++</code> 的实现和 <code>++</code> 的实现很接近, 唯一不同的前者是加自己, 后者是加值为 <code>(1.0, 1.0)</code> 的向量.</p>
|
||||
<pre><code class="lang-swift">var toBeDoubled = Vector2D(x: 1.0, y: 4.0)
|
||||
let afterDoubling = +++toBeDoubled
|
||||
// toBeDoubled 现在是 (2.0, 8.0)
|
||||
// afterDoubling 现在也是 (2.0, 8.0)
|
||||
</code></pre><h3 id="-">自定义中置运算符的优先级和结合性</h3>
|
||||
</code></pre>
|
||||
<h3 id="-">自定义中置运算符的优先级和结合性</h3>
|
||||
<p>可以为自定义的中置运算符指定优先级和结合性。可以回头看看<a href="#PrecedenceandAssociativity">优先级和结合性</a>解释这两个因素是如何影响多种中置运算符混合的表达式的计算的。</p>
|
||||
<p>结合性(associativity)的值可取的值有<code>left</code>,<code>right</code>和<code>none</code>。左结合运算符跟其他优先级相同的左结合运算符写在一起时,会跟左边的操作数结合。同理,右结合运算符会跟右边的操作数结合。而非结合运算符不能跟其他相同优先级的运算符写在一起。</p>
|
||||
<p>结合性(associativity)的值默认为<code>none</code>,优先级(precedence)默认为<code>100</code>。</p>
|
||||
<p>以下例子定义了一个新的中置符<code>+-</code>,是左结合的<code>left</code>,优先级为<code>140</code>。</p>
|
||||
<pre><code>operator infix +- { associativity left precedence 140 }
|
||||
<pre><code class="lang-swift">operator infix +- { associativity left precedence 140 }
|
||||
func +- (left: Vector2D, right: Vector2D) -> Vector2D {
|
||||
return Vector2D(x: left.x + right.x, y: left.y - right.y)
|
||||
}
|
||||
@ -865,7 +894,8 @@ let firstVector = Vector2D(x: 1.0, y: 2.0)
|
||||
let secondVector = Vector2D(x: 3.0, y: 4.0)
|
||||
let plusMinusVector = firstVector +- secondVector
|
||||
// plusMinusVector 此时的值为 (4.0, -2.0)
|
||||
</code></pre><p>这个运算符把两个向量的<code>x</code>相加,把向量的<code>y</code>相减。因为他实际是属于加减运算,所以让它保持了和加法一样的结合性和优先级(<code>left</code>和<code>140</code>)。查阅完整的Swift默认结合性和优先级的设置,请移步<a href="../chapter3/04_Expressions.html">表达式</a>;</p>
|
||||
</code></pre>
|
||||
<p>这个运算符把两个向量的<code>x</code>相加,把向量的<code>y</code>相减。因为他实际是属于加减运算,所以让它保持了和加法一样的结合性和优先级(<code>left</code>和<code>140</code>)。查阅完整的Swift默认结合性和优先级的设置,请移步<a href="../chapter3/04_Expressions.html">表达式</a>;</p>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="3.1" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="3.1" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="3.2" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="3.2" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
@ -657,10 +657,11 @@
|
||||
<p><a name="literals"></a></p>
|
||||
<h2 id="-">字面量</h2>
|
||||
<p>字面值表示整型、浮点型数字或文本类型的值,举例如下:</p>
|
||||
<pre><code>42 // 整型字面量
|
||||
<pre><code class="lang-swift">42 // 整型字面量
|
||||
3.14159 // 浮点型字面量
|
||||
"Hello, world!" // 文本型字面量
|
||||
</code></pre><blockquote>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>字面量语法</p>
|
||||
<p><em>literal</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/integer-literal" target="_blank">integer-literal</a> | <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/floating-point-literal" target="_blank">floating-point-literal</a> | <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/string-literal" target="_blank">string-literal</a></p>
|
||||
</blockquote>
|
||||
@ -669,9 +670,10 @@
|
||||
<p>十进制字面量包含数字 <code>0</code> 至 <code>9</code>。二进制字面量只包含 <code>0</code> 或 <code>1</code>,八进制字面量包含数字 <code>0</code> 至 <code>7</code>,十六进制字面量包含数字 <code>0</code> 至 <code>9</code> 以及字母 <code>A</code> 至 <code>F</code> (大小写均可)。</p>
|
||||
<p>负整数的字面量在数字前加减号 <code>-</code>,比如 <code>-42</code>。</p>
|
||||
<p>允许使用下划线 <code>_</code> 来增加数字的可读性,下划线不会影响字面量的值。整型字面量也可以在数字前加 <code>0</code>,同样不会影响字面量的值。</p>
|
||||
<pre><code>1000_000 // 等于 1000000
|
||||
<pre><code class="lang-swift">1000_000 // 等于 1000000
|
||||
005 // 等于 5
|
||||
</code></pre><p>除非特殊指定,整型字面量的默认类型为 Swift 标准库类型中的 <code>Int</code>。Swift 标准库还定义了其他不同长度以及是否带符号的整数类型,请参考 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_411" target="_blank">整数类型</a>。</p>
|
||||
</code></pre>
|
||||
<p>除非特殊指定,整型字面量的默认类型为 Swift 标准库类型中的 <code>Int</code>。Swift 标准库还定义了其他不同长度以及是否带符号的整数类型,请参考 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_411" target="_blank">整数类型</a>。</p>
|
||||
<blockquote>
|
||||
<p>整型字面量语法</p>
|
||||
<p><em>integer-literal</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/binary-literal" target="_blank">binary-literal</a></p>
|
||||
@ -703,9 +705,10 @@
|
||||
<p>十六进制浮点型字面量(<em>hexadecimal floating-point literals</em>)由前缀 <code>0x</code> 后跟可选的十六进制小数部分以及十六进制指数部分组成。十六进制小数部分由小数点后跟十六进制数字串组成。指数部分由大写或小写字母 <code>p</code> 后跟十进制数字串组成,这串数字表示 <code>p</code> 之前的数量乘以 2 的几次方。例如:<code>0xFp2</code> 表示 <code>15 ⨉ 2^2</code>,也就是 <code>60</code>;同样,<code>0xFp-2</code> 表示 <code>15 ⨉ 2^-2</code>,也就是 <code>3.75</code>。</p>
|
||||
<p>与整型字面量不同,负的浮点型字面量由一元运算符减号 <code>-</code> 和浮点型字面量组成,例如 <code>-42.0</code>。这代表一个表达式,而不是一个浮点整型字面量。</p>
|
||||
<p>允许使用下划线 <code>_</code> 来增强可读性,下划线不会影响字面量的值。浮点型字面量也可以在数字前加 <code>0</code>,同样不会影响字面量的值。</p>
|
||||
<pre><code>10_000.56 // 等于 10000.56
|
||||
<pre><code class="lang-swift">10_000.56 // 等于 10000.56
|
||||
005000.76 // 等于 5000.76
|
||||
</code></pre><p>除非特殊指定,浮点型字面量的默认类型为 Swift 标准库类型中的 <code>Double</code>,表示64位浮点数。Swift 标准库也定义 <code>Float</code> 类型,表示32位浮点数。</p>
|
||||
</code></pre>
|
||||
<p>除非特殊指定,浮点型字面量的默认类型为 Swift 标准库类型中的 <code>Double</code>,表示64位浮点数。Swift 标准库也定义 <code>Float</code> 类型,表示32位浮点数。</p>
|
||||
<blockquote>
|
||||
<p>浮点型字面量语法</p>
|
||||
<p><em>floating-point-literal</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/decimal-literal" target="_blank">decimal-literal</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/decimal-fraction" target="_blank">decimal-fraction</a> <em>opt</em> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/decimal-exponent" target="_blank">decimal-exponent</a> <em>opt</em></p>
|
||||
@ -741,11 +744,12 @@
|
||||
<p>后跟的数字表示一个 Unicode 码点。</p>
|
||||
<p>文本型字面量允许在反斜线小括号 <code>\()</code> 中插入表达式的值。插入表达式(<em>interpolated expression</em>)不能包含未转义的双引号 <code>"</code>、反斜线 <code>\</code>、回车符或者换行符。表达式值的类型必须在 <em>String</em> 类中有对应的初始化方法。</p>
|
||||
<p>例如,以下所有文本型字面量的值相同:</p>
|
||||
<pre><code>"1 2 3"
|
||||
<pre><code class="lang-swift">"1 2 3"
|
||||
"1 2 \(3)"
|
||||
"1 2 \(1 + 2)"
|
||||
var x = 3; "1 2 \(x)"
|
||||
</code></pre><p>文本型字面量的默认类型为 <code>String</code>。组成字符串的字符类型为 <code>Character</code>。更多有关 <code>String</code> 和 <code>Character</code> 的信息请参照 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_368" target="_blank">字符串和字符</a>。</p>
|
||||
</code></pre>
|
||||
<p>文本型字面量的默认类型为 <code>String</code>。组成字符串的字符类型为 <code>Character</code>。更多有关 <code>String</code> 和 <code>Character</code> 的信息请参照 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_368" target="_blank">字符串和字符</a>。</p>
|
||||
<blockquote>
|
||||
<p>文本型字面量语法</p>
|
||||
<p><em>string-literal</em> → <strong>"</strong> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/quoted-text" target="_blank">quoted-text</a> <strong>"</strong></p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="3.3" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="3.3" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="3.4" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="3.4" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="3.6" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="3.6" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="3.7" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="3.7" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="3.8" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="3.8" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="3.9" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="3.9" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="3.5" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="3.5" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="3" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="3" data-basepath=".." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -44,7 +44,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="0" data-basepath="." data-revision="1402617910282">
|
||||
<div class="book" data-level="0" data-basepath="." data-revision="1402634093001">
|
||||
<div class="book-header">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
CACHE MANIFEST
|
||||
# Revision 1402617910283
|
||||
# Revision 1402634093002
|
||||
|
||||
CACHE:
|
||||
index.html
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user