原文链接  http://www.cocoachina.com/swift/20141002/9779.html

虽然 Objective-C 的语法相对于其他编程语言来说写法有点奇怪,但是当你真正使用的时候它的语法还是相当的简单。下面有一些例子:

1
2
3
4
5
6
7
8
9
10
11
+ (void)mySimpleMethod
{    // 类方法
    // 无参数
    // 无返回值}
- (NSString *)myMethodNameWithParameter1:(NSString *)param1 parameter2:(NSNumber *)param2
{    // 实例方法
    // 其中一个参数是 NSString 指针类型,另一个是 NSNumber 指针类型
    // 必须返回一个 NSString 指针类型的值
    return @"hello, world!";
}

相比而言,虽然 Swift 的语法看起来与其他编程语言有更多相似的地方,但是它也可以比 Objective-C 更加复杂和令人费解。

在继续之前,我需要澄清 Swift 中方法函数之间的不同,因为在本文中我们将使用这两个术语。按照 Apple 的 Swift Programming Language Book 里面的方法定义:

方法是与某些特定类型相关联的函数。类、结构体、枚举都可以定义实例方法;实例方法为给定类型的实例封装了具体的任务与功能。类、结构体、枚举 也可以定义类型方法,类型方法与类型本身相关联。类型方法与 Objective-C 中的类方法(class methods)相似。

以上是长文慎读。一句话:函数是独立的,而方法是函数封装在类,结构或者枚举中的函数。

剖析 Swift 函数

让我们从简单的 “Hello,World” Swift 函数开始:

1
2
3
func mySimpleFunction() {
    println("hello, world!")
}

如果你曾在 Objective-C 之外的语言进行过编程,上面的这个函数你会非常熟悉

  • func 表示这是一个函数。

  • 函数的名称是 mySimpleFunction

  • 这个函数没有参数传入 - 因此是( )

  • 函数没有返回值

  • 函数是在{ }中执行

现在让我们看一个稍稍复杂的例子:

1
2
3
func myFunctionName(param1: String, param2: Int) -> String {
    return "hello, world!"
}

这个函数有一个 String 类型且名为 param1 的参数和一个 Int 类型名为 param2 的参数并且返回值是 `String 类型。

调用所有函数

Swift 和 Objective-C 之间其中一个巨大的差别就是当 Swift 函数被调用的时候参数工作方式。如果你像我一样喜欢 Objective-C 超长的命名方式,那么请记住,在默认情况下 Swift 函数被调用时参数名是不被外部调用包含在内的。

1
2
3
4
5
func hello(name: String) {
    println("hello \(name)")
}
hello("Mr. Roboto")

在你增加更多参数到函数之前,一切看起来不是那么糟糕。但是:

1
2
3
4
5
func hello(name: String, age: Int, location: String) {
    println("Hello \(name). I live in \(location) too. When is your \(age + 1)th birthday?")
}
hello("Mr. Roboto", 5, "San Francisco")

如果仅阅读 hello("Mr. Roboto", 5, "San Francisco"),你可能很难知道每一个参数代表什么。

在 Swift 中,有一个概念称为 *外部参数名称 * 用来解决这个困惑:

1
2
3
4
5
func hello(fromName name: String) {
    println("\(name) says hello to you!")
}
hello(fromName: "Mr. Roboto")

上面函数中,fromName 是一个外部参数,在函数被调用的时候将被包括在调用中。在函数内执行时,使用 name 这个内部参数来对输入进行引用。

如果你希望外部参数和内部参数相同,你不需要写两次参数名:

1
2
3
4
5
func hello(name name: String) {
    println("hello \(name)")
}
hello(name: "Robot")

只需要在参数前面添加 # 的快捷方式:

1
2
3
4
5
func hello(name name: String) {
    println("hello \(name)")
}
hello(name: "Robot")

当然,对于方法而言参数的工作方式略有不同...

调用方法

当被封装在类 (或者结构,枚举) 中时,方法的第一个参数名被外部包含,同时所有的后面的参数在方法调用时候被外部包含:

1
2
3
4
5
6
7
8
9
10
class MyFunClass {
    func hello(name: String, age: Int, location: String) {
        println("Hello \(name). I live in \(location) too. When is your \(age + 1)th birthday?")
    }
}
let myFunClass = MyFunClass()
myFunClass.hello("Mr. Roboto", age: 5, location: "San Francisco")

因此最佳实践是在方法名里包含第一个参数名,就像 Objective-C 那样:

1
2
3
4
5
6
7
8
9
10
class MyFunClass {
    func helloWithName(name: String, age: Int, location: String) {
        println("Hello \(name). I live in \(location) too. When is your \(age + 1)th birthday?")
    }
}
let myFunClass = MyFunClass()
myFunClass.helloWithName("Mr. Roboto", age: 5, location: "San Francisco")

相对于调用函数 “hello”,我将其重命名为 helloWithName,这使得第一个参数 name 变得很清晰。

如果出于一些原因你希望在函数中跳过外部参数名 (我建议如果要这么做的话,你需要一个非常好的理由),为外部函数添加 _ 来解决:

1
2
3
4
5
6
7
8
9
10
class MyFunClass {
    func helloWithName(name: String, _ age: Int, _ location: String) {
        println("Hello \(name). I live in \(location) too. When is your \(age + 1)th birthday?")
    }
}
let myFunClass = MyFunClass()
myFunClass.helloWithName("Mr. Roboto", 5, "San Francisco")

实例方法是柯里化 (currying) 函数

需要注意一个非常酷的是 Swift 中实例方法是柯里化函数。

柯里化背后的基本想法是函数可以局部应用,意思是一些参数值可以在函数调用之前被指定或者绑定。这个部分函数的调用会返回一个新的函数。

如果我有一个类:

1
2
3
4
5
6
class MyHelloWorldClass {
    func helloWithName(name: String) -> String {
        return "hello, \(name)"
    }
}

我可以建立一个变量指向类中的 helloWithName 函数:

1
2
let helloWithNameFunc = MyHelloWorldClass.helloWithName
// MyHelloWorldClass -> (String) -> String

我新的 helloWithNameFunc 是 MyHelloWorldClass -> (String) -> String 类型,这个函数接受我的类的实例并返回另一个函数。新函数接受一个字符串值,并返回一个字符串值。

所以实际上我可以这样调用我的函数:

1
2
3
4
let myHelloWorldClassInstance = MyHelloWorldClass()
helloWithNameFunc(myHelloWorldClassInstance)("Mr. Roboto"
// hello, Mr. Roboto

初始化:一个特殊注意的地方

在类,结构体或者枚举初始化的时候将调用一个特殊的 init 方法。在 Swift 中你可以像其他方法那样定义初始化参数:

1
2
3
4
5
6
7
8
9
10
class Person {
    init(name: String) {
        // your init implementation
        // 你的初始化方法实现
    }
}
Person(name: "Mr. Roboto")

注意下,不像其他方法,初始化方法的第一个参数必须在实例时必须是外部的。

大多数情况下的最佳实践是添加一个不同的外部参数名 — 本例中的 fromName —让初始化更具有可读性:

1
2
3
4
5
6
7
8
9
10
class Person {
    init(fromName name: String) {
        // your init implementation
        // 你的初始化方法实现
    }
}
Person(fromName: "Mr. Roboto")

当然,就像其他方法那样,如果你想让方法跳过外部参数名的话,可以添加 _。我喜欢  Swift Programming Language Book 初始化例子的强大和可读性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct Celsius {
    var temperatureInCelsius: Double
    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
    init(fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
    init(_ celsius: Double) {
        temperatureInCelsius = celsius
    }
}
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
// boilingPointOfWater.temperatureInCelsius 是 100.0
let freezingPointOfWater = Celsius(fromKelvin: 273.15)
// freezingPointOfWater.temperatureInCelsius 是 0.0
let bodyTemperature = Celsius(37.0)
// bodyTemperature.temperatureInCelsius 是 37.0

如果你希望抽象类/枚举/结构体的初始化,跳过外部参数可以非常有用。我喜欢在 David Owen 的 json-swift library 中对这项技术的使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public struct JSValue : Equatable {
    // ... 截断的部分代码
    /// 使用 `JSArrayType` 来初始化 `JSValue`。 
    public init(_ value: JSArrayType) {
        self.value = JSBackingValue.JSArray(value)
    }
    /// 使用 `JSObjectType` 来初始化 `JSValue`。 
    public init(_ value: JSObjectType) {
        self.value = JSBackingValue.JSObject(value)
    }
    /// 使用 `JSStringType` 来初始化 `JSValue`。 
    public init(_ value: JSStringType) {
        self.value = JSBackingValue.JSString(value)
    }
    /// 使用 `JSNumberType` 来初始化 `JSValue`。
    public init(_ value: JSNumberType) {
        self.value = JSBackingValue.JSNumber(value)
    }
    /// 使用 `JSBoolType` 来初始化 `JSValue`。
    public init(_ value: JSBoolType) {
        self.value = JSBackingValue.JSBool(value)
    }
    /// 使用 `Error` 来初始化 `JSValue`。
    init(_ error: Error) {
        self.value = JSBackingValue.Invalid(error)
    }
    /// 使用 `JSBackingValue` 来初始化 `JSValue`。
    init(_ value: JSBackingValue) {
        self.value = value
    }
}

华丽的参数

相较于 Objective-C,Swift 有很多额外的选项用来指定可以传入的参数的类型,下面是一些例子。

可选参数类型

在 Swift 中有一个新的概念称之为 optional types:

可选表示 “那儿有一个值,并且它等于 x ” 或者 “那儿没有值”。可选有点像在 Objective-C 中使用  nil,但是它可以用在任何类型上,不仅仅是类。可选类型比 Objective-C 中的 nil 指针更加安全也更具表现力,它是 Swift  许多强大特性的重要组成部分。

表明一个参数是可选 (可以是 nil),可以在类型规范后添加一个问号:

1
2
3
4
5
6
func myFuncWithOptionalType(parameter: String?) {
    // function execution
}
myFuncWithOptionalType("someString")
myFuncWithOptionalType(nil)

使用可选时候不要忘记拆包!

1
2
3
4
5
6
7
8
9
10
11
12
13
func myFuncWithOptionalType(optionalParameter: String?) {
    if let unwrappedOptional = optionalParameter {
        println("The optional has a value! It's \(unwrappedOptional)")
    else {
        println("The optional is nil!")
    }
}
myFuncWithOptionalType("someString")
// optional has a value! It's someString
myFuncWithOptionalType(nil)
// The optional is nil

如果学习过 Objective-C,那么习惯使用可选值肯定需要一些时间!

参数默认值

1
2
3
4
5
6
7
8
9
func hello(name: String = "you") {
    println("hello, \(name)")
}
hello(name: "Mr. Roboto")
// hello, Mr. Roboto
hello()
// hello, you

值得注意的是有默认值的参数自动包含一个外部参数名

由于参数的默认值可以在函数被调用时调过,所以最佳实践是把含有默认值的参数放在函数参数列表的最后。Swift Programming Language Book 包含相关的内容介绍:

把含有默认值的参数放在参数列表最后,可以确保对它的调用中所有无默认值的参数顺序一致,而且清晰表述了在不同情况下调用的函数是相同的。

我是默认参数的粉丝,主要是它使得代码容易改变而且向后兼容。比如配置一个自定义的 UITableViewCell 的函数里,你可以在你的某个用例中用两个参数开始,如果另一个用例出现,需要另一个参数 (比如你的 Cell 的 label  含有不同文字颜色),只需要添加一个包含新默认值的参数 — 函数的其他部分已经被正确调用,并且你代码最新部分仅需要参数传入一个非默认值。

可变参数

可变参数是传入数组元素的一个更加可读的版本。实际上,比如下面例子中的内部参数名类型,你可以看到它是 [String] 类型 (String 数组):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func helloWithNames(names: String...) {
    for name in names {
        println("Hello, \(name)")
    }
}
// 2 names
helloWithNames("Mr. Robot""Mr. Potato")
// Hello, Mr. Robot
// Hello, Mr. Potato
// 4 names
helloWithNames("Batman""Superman""Wonder Woman""Catwoman")
// Hello, Batman
// Hello, Superman
// Hello, Wonder Woman
// Hello, Catwoman

这里要特别记住的是可以传入 0 个值,就像传入一个空数组一样,所以如果有必要的话,不要忘记检查空数组:

1
2
3
4
5
6
7
8
9
10
11
12
func helloWithNames(names: String...) {
    if names.count > 0 {
        for name in names {
            println("Hello, \(name)")
        }
    else {
        println("Nobody here!")
    }
}
helloWithNames()
// Nobody here!

可变参数另一个要注意的地方是 — 可变参数必须是在函数列表的最后一个!

输入输出参数 inout

利用 inout 参数,你有能力 (经过引用来) 操纵外部变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var name1 = "Mr. Potato"
var name2 = "Mr. Roboto"
func nameSwap(inout name1: String, inout name2: String) {
    let oldName1 = name1
    name1 = name2
    name2 = oldName1
}
nameSwap(&name1, &name2)
name1
// Mr. Roboto
name2
// Mr. Potato

这是 Objective-C 中非常常见的用来处理错误的模式。 NSJSONSerialization 是其中一个例子:

1
2
3
4
5
6
7
8
9
- (void)parseJSONData:(NSData *)jsonData
{
    NSError *error = nil;
    id jsonResult = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
    if (!jsonResult) {
        NSLog(@"ERROR: %@", error.description);
    }
}

Swift 非常之新,所以这里没有一个公认的处理错误的方式,但是在 inout 参数之外肯定有非常多的选择!看看 David Owen's  最新的博客 Swfit 中的错误处理。关于这个话题的更多内容已经在 Functional Programming in Swift 中被涵盖.

泛型参数类型

我不会在本文中大篇幅介绍泛型,但是这里有个简单的例子来阐述如何在一个函数中接受两个类型不定的参数,但确保这两个参数类型是相同的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func valueSwap(inout value1: T, inout value2: T) {
    let oldValue1 = value1
    value1 = value2
    value2 = oldValue1
}
var name1 = "Mr. Potato"
var name2 = "Mr. Roboto"
valueSwap(&name1, &name2)
name1 // Mr. Roboto
name2 // Mr. Potato
var number1 = 2
var number2 = 5
valueSwap(&number1, &number2)
number1 // 5
number2 // 2

更多的泛型知识,我建议你阅读下 Swift Programming Language book 中的泛型章节。

变量参数 var

默认情况下,参数传入函数是一个常量,所以它们在函数范围内不能被操作。如果你想修改这个行为,只需要在你的参数前使用 var 关键字:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
var name = "Mr. Roboto"
func appendNumbersToName(var name: String, #maxNumber: Int) -> String {
    for in 0..<maxnumber {         name +=" String(i + 1)"     }=""     return name="" }="" appendnumberstoname(name, maxnumber:5)=""  mr. robot12345="" name=""  mr. roboto<="" pre="">
<p> 值得注意的是这个和 inout 参数不同 — 变量参数不会修改外部传入变量!</p>
<p><strong>作为参数的函数</strong></p>
<p>在 Swift 中,函数可以被用来当做变量传递。比如,一个函数可以含有一个函数类型的参数:</p>
<pre class="brush:js;toolbar:false">func luckyNumberForName(name: String, #lotteryHandler: (String, Int) -> String) -> String {
    let luckyNumber = Int(arc4random() % 100)
    return lotteryHandler(name, luckyNumber)
}
func defaultLotteryHandler(name: String, luckyNumber: Int) -> String {
    return "\(name), your lucky number is \(luckyNumber)"
}
luckyNumberForName("Mr. Roboto", lotteryHandler: defaultLotteryHandler)
// Mr. Roboto, your lucky number is 38</pre>
<p>注意下只有函数的引用被传入 — 在本例中是 <code>defaultLotteryHandler</code>。这个函数之后是否执行是由接收的函数决定。</p>
<p>实例方法也可以用类似的方法传入:</p>
<pre class="brush:js;toolbar:false">func luckyNumberForName(name: String, #lotteryHandler: (String, Int) -> String) -> String {
    let luckyNumber = Int(arc4random() % 100)
    return lotteryHandler(name, luckyNumber)
}
class FunLottery {
    func defaultLotteryHandler(name: String, luckyNumber: Int) -> String {
        return "\(name), your lucky number is \(luckyNumber)"
    }
}
let funLottery = FunLottery()
luckyNumberForName("Mr. Roboto", lotteryHandler: funLottery.defaultLotteryHandler)
// Mr. Roboto, your lucky number is 38</pre>
<p>为了让你的函数定义更具可读性,可以考虑为你函数的类型创建别名 (类似于 Objective-C 中的 typedef):</p>
<pre class="brush:js;toolbar:false">typealias lotteryOutputHandler = (String, Int) -> String
func luckyNumberForName(name: String, #lotteryHandler: lotteryOutputHandler) -> String {
    let luckyNumber = Int(arc4random() % 100)
    return lotteryHandler(name, luckyNumber)
}</pre>
<p>你也可以使用不包含参数名的函数 (类似于 Objective-C 中的 blocks):</p>
<pre class="brush:js;toolbar:false">func luckyNumberForName(name: String, #lotteryHandler: (String, Int) -> String) -> String {
    let luckyNumber = Int(arc4random() % 100)
    return lotteryHandler(name, luckyNumber)
}
luckyNumberForName("Mr. Roboto", lotteryHandler: {name, number in
    return "\(name)'s' lucky number is \(number)"
})
// Mr. Roboto's lucky number is 74</pre>
<p>在 Objective-C 中,使用 blocks 作为参数是异步操作是操作结束时的回调和错误处理的常见方式,这一方式在 Swift 中得到了很好的延续。</p>
<p><strong>权限控制</strong></p>
<p>Swift 有三个级别的<a href="https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/Swift_Programming_Language/AccessControl.html">权限控制</a>:</p>
<ul class=" list-paddingleft-2">
    <li>
    <p><strong>Public 权限</strong> 可以为实体启用定义它们的模块中的源文件的访问,另外其他模块的源文件里只要导入了定义模块后,也能进行访问。通常情况下,Framework 是可以被任何人使用的,你可以将其设置为 public 级别</p>
    </li>
    <li>
    <p><strong>Internal 权限</strong> 可以为实体启用定义它们的模块中的源文件的访问,但是在定义模块之外的任何源文件中都不能访问它。通常情况下,app 或 Framework 的内部结构使用 internal 级别。</p>
    </li>
    <li>
    <p><strong>Private 权限</strong> 只能在当前源文件中使用的实体。使用 private 级别,可以隐藏某些功能的特地的实现细节。</p>
    </li>
</ul>
<p>默认情况下,每个函数和变量是 internal 的 —— 如果你希望修改他们,你需要在每个方法和变量的前面使用 <code>private</code> 或者 <code>public</code> 关键字:</p>
<pre class="brush:js;toolbar:false">public func myPublicFunc() {
}
func myInternalFunc() {
}
private func myPrivateFunc() {
}
private func myOtherPrivateFunc() {
}</pre>
<p>Ruby 带来的习惯,我喜欢把所有的私有函数放在类的最下面,利用一个 <code>//MARK</code> 来区分:</p>
<pre class="brush:js;toolbar:false">class MyFunClass {
    func myInternalFunc() {
    }
    // MARK: Private Helper Methods
    private func myPrivateFunc() {
    }
    private func myOtherPrivateFunc() {
    }
}</pre>
<p>希望 Swift 在将来的版本中包含一个选项可以用一个私有关键字来表明以下所有的方法都是私有的,类似于其他语言那样做访问控制。</p>
<p><strong>华丽的返回类型</strong></p>
<p>在 Swift 中,函数的返回类型和返回值相较于 Objective-C 而言更加复杂,尤其是引入可选和多个返回类型。</p>
<p><strong>可选返回类型</strong></p>
<p>如果你的函数有可能返回一个 nil 值,你需要指定返回类型为可选:</p>
<pre class="brush:js;toolbar:false">func myFuncWithOptonalReturnType() -> String? {
    let someNumber = arc4random() % 100
    if someNumber > 50 {
        return "someString"
    else {
        return nil
    }
}
myFuncWithOptonalReturnType()</pre>
<p>当然,当你使用可选返回值,不要忘记拆包:</p>
<pre class="brush:js;toolbar:false">let optionalString = myFuncWithOptonalReturnType()
if let someString = optionalString {
    println("The function returned a value: \(someString)")
else {
    println("The function returned nil")
}</pre>
<p>The best explanation I've seen of optionals is from a <a href="https://twitter.com/Kronusdark/status/496444128490967041">tweet by @Kronusdark</a>: <br>
对我而言最好的可选值的解释来自于 <a href="https://twitter.com/Kronusdark/status/496444128490967041">@Kronusdark</a> 的一条推特:</p>
<blockquote>
<p>我终于弄明白 @SwiftLang 的可选值了,它们就像薛定谔的猫!在你使用之前,你必须先看看猫是死是活。</p>
</blockquote>
<p><strong>多返回值</strong></p>
<p>Swift 其中一个令人兴奋的功能是函数可以有多个返回值</p>
<pre class="brush:js;toolbar:false">func findRangeFromNumbers(numbers: Int...) -> (min: Int, max: Int) {
    var min = numbers[0]
    var max = numbers[0]
    for number in numbers {
        if number > max {
            max = number
        }
        if number < min {
            min = number
        }
    }
    return (min, max)
}
findRangeFromNumbers(1, 234, 555, 345, 423)
// (1, 555)</pre>
<p>就像你看到的那样,在一个元组中返回多个值,这一个非常简单的将值进行组合的数据结构。有两种方法可以使用多返回值的元组:</p>
<pre class="brush:js;toolbar:false">let range = findRangeFromNumbers(1, 234, 555, 345, 423)
println("From numbers: 1, 234, 555, 345, 423. The min is \(range.min). The max is \(range.max).")
// From numbers: 1, 234, 555, 345, 423. The min is 1. The max is 555.
let (min, max) = findRangeFromNumbers(236, 8, 38, 937, 328)
println("From numbers: 236, 8, 38, 937, 328. The min is \(min). The max is \(max)")
// From numbers: 236, 8, 38, 937, 328. The min is 8. The max is 937</pre>
<p><strong>多返回值与可选值</strong></p>
<p>当返回值是可选的时候,多返回值就比较棘手。对于多个可选值的返回,有两种办法解决这种情况。</p>
<p>在上面的例子函数中,我的逻辑是有缺陷的 —— 它有可能没有值传入,所以我的代码有可能在没有值传入的时候崩溃,所以我希望我整个返回值是可选的:</p>
<pre class="brush:js;toolbar:false">func findRangeFromNumbers(numbers: Int...) -> (min: Int, max: Int)? {
    if numbers.count > 0 {
        var min = numbers[0]
        var max = numbers[0]
        for number in numbers {
            if number > max {
                max = number
            }
            if number < min {
                min = number
            }
        }
        return (min, max)
    else {
        return nil
    }
}
if let range = findRangeFromNumbers() {
    println("Max: \(range.max). Min: \(range.min)")
else {
    println("No numbers!")
}
// No numbers!</pre>
<p>另一种做法是对元组中的每个返回值设为可选来代替整体的元组可选:</p>
<pre class="brush:js;toolbar:false">func componentsFromUrlString(urlString: String) -> (host: String?, path: String?) {
    let url = NSURL(string: urlString)
    return (url.host, url.path)
}</pre>
<p>如果你决定你元组值中一些值是可选,拆包时候会变得有些复杂,你需要考虑每中单独的可选返回值的组合:</p>
<pre class="brush:js;toolbar:false">let urlComponents = componentsFromUrlString("http://name.com/12345;param?foo=1&baa=2#fragment")
switch (urlComponents.host, urlComponents.path) {
case let (.Some(host), .Some(path)):
    println("This url consists of host \(host) and path \(path)")
case let (.Some(host), .None):
    println("This url only has a host \(host)")
case let (.None, .Some(path)):
    println("This url only has path \(path). Make sure to add a host!")
case let (.None, .None):
    println("This is not a url!")
}
// This url consists of host name.com and path /12345</pre>
<p>如你所见,它和 Objective-C 的处理方式完全不同!</p>
<p><strong>返回一个函数</strong></p>
<p>Swift 中函数可以返回一个函数:</p>
<pre class="brush:js;toolbar:false">func myFuncThatReturnsAFunc() -> (Int) -> String {
    return { number in
        return "The lucky number is \(number)"
    }
}
let returnedFunction = myFuncThatReturnsAFunc()
returnedFunction(5) // The lucky number is 5</pre>
<p>为了更具有可读性,你当然可以为你的返回函数定义一个别名:</p>
<pre class="brush:js;toolbar:false">typealias returnedFunctionType = (Int) -> String
func myFuncThatReturnsAFunc() -> returnedFunctionType {
    return { number in
        return "The lucky number is \(number)"
    }
}
let returnedFunction = myFuncThatReturnsAFunc()
returnedFunction(5) // The lucky number is 5</pre>
<p><strong>嵌套函数</strong></p>
<p>如果在这篇文章中你没对函数有足够的体会,那么了解下 Swift 可以在函数中定义函数也是不错的。</p>
<pre class="brush:js;toolbar:false">func myFunctionWithNumber(someNumber: Int) {
    func increment(var someNumber: Int) -> Int {
        return someNumber + 10
    }
    let incrementedNumber = increment(someNumber)
    println("The incremeted number is \(incrementedNumber)")
}
myFunctionWithNumber(5)
// The incremeted number is 15</pre>
<p><strong>@end</strong></p>
<p>Swift 函数有更多的选项以及更为强大功能。从你开始利用 Swift 编程时,记住:能力越强责任越大。请一定要巧妙地优化可读性!</p>
<p>Swift 的最佳实践还没被确立,这门语言也在不断地进化,所以请朋友和同事来审查你的代码。我发现一些从来没见过 Swift 的人反而在我的 Swift 代码中提供了很大帮助。</p>
<p>Swift 编码快乐!</p></maxnumber {>

转载 Swift方法的多面性相关推荐

  1. Swift 方法的多面性

    虽然 Objective-C 的语法相对于其他编程语言来说写法有点奇怪,但是当你真正使用的时候它的语法还是相当的简单.下面有一些例子: + (void)mySimpleMethod {// 类方法// ...

  2. tensorflow 语音识别_调研报告|在线语音识别改进方法之序列区分性训练

    这篇文章主要调研的是一种常见的改进在线语音识别的方法:序列区分性训练(Sequence Discriminative Training).相信有很多人已经在 CTC/CE 的训练上遇到了瓶颈,而一些新 ...

  3. Swift中方法的多面性

    虽然 Objective-C 的语法相对于其他编程语言来说写法有点奇怪,但是当你真正使用的时候它的语法还是相当的简单.下面有一些例子: + (void)mySimpleMethod {// 类方法// ...

  4. swift 方法的局部和外部参数名

    一.什么是外部参数名? 浅显地说,外部参数名就是在调用一个方法时要在方法的参数前面加上一个特定的名字,目的是便于阅读代码,提高维护效率. 二.在最新的Xcode中,外部参数名的性质与用法如下 性质: ...

  5. [转载]Python方法绑定——Unbound/Bound method object的一些梳理

    本篇主要总结Python中绑定方法对象(Bound method object)和未绑定方法对象(Unboud method object)的区别和联系. 主要目的是分清楚这两个极容易混淆的概念,顺便 ...

  6. Unity射击游戏发射子弹的方法和提升流畅性的小技巧

    引言 在某些射击游戏里(2D和3D都适用),可能你需要创建子弹,第一想到的可能是新建一个发射子弹的脚本,就叫BulletController,然后每次按下什么键就直接上Instantiate函数. 伪 ...

  7. Swift方法的简写

    本文来自斯坦福大学的iOS公开课-02 首先举个例子,一个计算器,需要最基本的加减乘除运算,代码如下 import Foundation//取操作数,假设已经取到如下 let op1 = 1.1; l ...

  8. 转载:正交表方法在创建测试套件上应用

    在Zee的专栏里有篇文章 OATS正交表法用于测试用例设计 介绍正交表的应用.实际上,它还可以用在优化Test Suite (测试套件.测试用例组),作用更大. 在测试中,特别是互联网应用,我们无法规 ...

  9. [转载] Java 方法(方法重载)与数组

    参考链接: Java中的方法重载和空错误 一.方法(Method) 1.方法的定义 1)方法定义与格式: 方法(Method),有人称之为函数(function),其实就指一个特定的功能操作,程序中能 ...

最新文章

  1. python【数据结构与算法】最小生成树之Kruskal算法
  2. 启动定时器t0的工作指令是_第六章 习题
  3. Same Sum Blocks
  4. Js计算间隔天数和Date对象
  5. 删除linux内核多余架构,删除多余Linux内核方法
  6. 从企业发展的角度来分析做网站的重要性
  7. mysql查询时间出来数字_mysql查询时间出来数字的解决方法
  8. 快照隔离(Snapshot Isolation)简单介绍和例子
  9. Launcher启动的流程图【AndroidICS4.0——Launcher系列四】
  10. 为什么只有软件就可以用盗版?
  11. mft文件记录属性头包括_学懂主流NTFS分区文件系统,你也可以成为MM眼中的大神!...
  12. 【ArcGIS教程01】前言
  13. “区块链+”教育的发展现状及其应用价值研究
  14. uniapp如何引入全局js
  15. 推荐几个短网址赚钱站
  16. Linux性能分析工具详解
  17. maya腿的蒙皮旋转枢轴_Maya更改枢轴点,MAYA
  18. (07)FPGA硬件描述语言
  19. GP2Y0A21YK0F距离传感器输出特性分析及其使用(IIC总线与PCF8591AD转换)+Proteus仿真(附源码)
  20. 「转」史上最详细 快递公司各种投诉内幕

热门文章

  1. 后羿采集器怎么导出数据_免费爬虫工具:后羿采集器如何采集同花顺圈子评论数据...
  2. ByRef和ByVal
  3. 利用OpenCV进行图像伽马校正
  4. 仿微信的录制小视频功能
  5. Spring框架中 自动装配的详解 属性值的详解
  6. 纯JS实现房贷利率报表对比
  7. Educode--头歌 《软件工程》实验作业2
  8. funny pics
  9. RJ45以太网接口EMC设计方案
  10. java拍照控件焦距问题,干货:监控中如何选择镜头焦距?