函数可以说是在编程语言中非常重要的一种语法类型,swift中,由于函数的语法与方法基本相同,所以从学习函数的语法开始来了解方法。
使用func
来声明一个函数,使用名字和参数来调用函数。使用->
来指定函数的返回值的类型。
func greet(name: String, day:String) -> String {
return "Hello \(name), today is \(day)"
}
greet("Bob", "Monday")
函数可以有多个返回值,使用元祖来使函数返回多个值。该元祖的元素可以用名字或数字来表示。
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
var min = score[0]
var max = score[0]
var sum = 0
for score in scores {
if min > score {
min = score
} else if max < score {
max = score
}
sum += score
}
return (min, max, sum)
}
let statistics = calculateStatisctics([2, 100, 30, 14, 89])
print(statistics.sum)
print(statistics.max)
此外函数还可以带一个可变个数的参数,这个参数在函数内表现为数组的形式:
func numOf(numbers: Int...) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
sumOf()
sumOf(42, 192, 63)
注意一个函数最多只能有一个可变参数。
函数还可以嵌套。被嵌套的函数可以访问外侧函数的变量,你可以使用嵌套函数来重构一个太长或者太复杂的函数。
func returnFifteen() -> Int { var y = 10
func add() {
y += 5
}
add()
return y
}
returnFifteen()
函数是第一等类型,这意味着函数可以作为另一个函数的返回值。
func makeIncrementer() -> (Int -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
increment(7)
函数也可以当做参数传给另一个函数。
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, 8, 23]
hasAnyMatches(numbers, condition: lessThanTen)
函数实际上是一种特殊的闭包:它是一段能之后调用的代码。闭包中的代码能访问闭包所建作用域中能得到的变量和函数,即使闭包是在一个不同的作用域中被执行 - 你已经在嵌套函数例子中所看到。你可以使用{}
来创建一个匿名闭包。使用in
将参数和返回值类型声明与闭包函数体进行分离。
numbers.map ({
(number: Int) -> Int in
let result = 3 * number
return number
})
有很多种创建更简洁的闭包的方法。如果一个闭包的类型已知,比如作为一个回调函数,你可以忽略参数的类型和返回值。单个语句闭包会把它语句的值当做结果返回。
let mappedNumbers = number.map({ number in 3 * number })
print (mappedNumbers)
你可以通过参数位置而不是参数名字来引用参数--这个方法在非常短的闭包中非常有用。当一个闭包作为最后一个参数传给一个函数的时候,它可以直接跟在括号后面。当一个闭包是传给函数的唯一参数,你可以完全忽略括号。
let sortedNumbers = number.sort{ $0 > $1 }
print(sortedNumbers)
变量参数和常量参数
函数参数默认是常量。试图在函数体中更改参数值将会导致编译错误。这意味着你不能错误地更改参数值。
但是,有时候,如果函数中有传入参数的变量值副本将是很有用的。你可以通过指定一个或多个参数为变量参数,从而避免自己在函数中定义新的变量。变量参数不是常量,你可以在函数中把它当做新的可修改副本来使用。
通过在参数名前加关键字var
来定义变量参数:
func alignRight(var string: String, totalLength: Int, pad: Character) -> String {
let amountToPad = totalLength - string.characters.count
if amountToPad < 1 {
return string
}
let padString = String(pad)
for _ in 1...amountToPad {
string = padString + string
}
return string
}
let originalString = "hello"
let paddedString = alignRight(originalString, totalLength: 10, pad: "-")
// paddedString is equal to "-----hello"
// originalString is still equal to "hello"
这个例子中定义了一个叫做 alignRight(_:totalLength:pad:)
的新函数,用来将输入的字符串对齐到更长的输出字符串的右边缘。左侧空余的地方用指定的填充字符填充。这个例子中,字符串"hello"
被转换成了"-----hello"
。
alignRight(_:totalLength:pad:)
函数将输入参数string
定义为变量参数。这意味着string
现在可以作为一个局部变量,被传入的字符串值初始化,并且可以在函数体中进行操作。
函数首先计算出有多少字符需要被添加到string
的左边,从而将其在整个字符串中右对齐。这个值存储在一个称为amountToPad
的本地常量。如果不需要填充(也就是说, 如果amountToPad
小于1),该函数简单地返回没有任何填充的输入值string
。
否则,该函数用pad
字符创建一个叫做padString
的临时String
常量,并将amountToPad
个padString
添加到现有字符串的左边。(一个String
值不能被添加到一个Character
值上,所以padString
常量用于确保+
操作符两侧都是String
值)。
注意
对变量参数所进行的修改在函数调用结束后便消失了,并且对于函数体外是不可见的。变量参数仅仅存在于函数 调用的生命周期中。
输入输出参数
变量参数,正如上面所述,仅仅能在函数体内被更改。如果你想要一个函数可以修改参数的值,并且想要在这些修改在函数调用结束后仍然存在,那么就应该把这个参数定义为输入输出参数。
定义一个输入输出参数时,在参数定义前加inout
关键字。一个输入输出参数有传入函数的值,这个值被函数修改,然后被传出函数,替换原来的值。
你只能传递变量给输入输出参数。你不能传入常量或者字面量(literal value),因为这些量是不能被修改的。当传入的参数作为输入输出参数时,需要在参数名前加&
符,表示这个值可以被函数修改。
注意
输入输出参数不能有默认值,而且可变参数不能用inout
标记。如果你用inout
标记一个参数,这个参数不能被var
或者let
标记。
下面是例子,swapTwoInts(_:_:)
函数,有两个分别叫做a
和b
的输入输出参数:
func swapTwoInts(inout a: Int, inout _ b: Int) {
let temporaryA = a
a= b
b = temporaryA
}
这个swapTwoInts(_:_:)
函数简单的交换a
和b
的值。该函数先将a
的值存到一个临时变量temporaryA
中,然后将b
的值赋给a
,最后将temporaryA
的值赋给b
。
你可以用两个Int
型变量来调用swapTwoInts(_:_:)
。需要注意的是someInt
和anotherInt
在传入swapTwoInts(_:_:)
函数前,都加了&
的前缀。
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// prints "someInt is now 107, and anotherInt is now 3"```
从上面的例子中,我们可以看到```someInt```和```anotherInt```的原始值在```swapTwoInts(_:_:)```函数中被修改,尽管他们的定义在函数体外。
>注意
输入输出参数和返回值是不一样的。上面的```swapTwoInts```函数并没有定义任何返回值,但仍然修改了```someInt```和```anotherInt```的值。输入输出参数是函数对函数体外产生影响的另一种方式。