函數(shù)
多參數(shù)
我們設(shè)計一個能求矩形面積的函數(shù),輸入長和寬,就得出面積:
func rectangle(length: Double, width: Double) -> Double {
return length * width
}
print(rectangle(length: 15, width: 20.8) ) // 312.0
這里,我們設(shè)計了length和width兩個參數(shù),分別代表了長方形的長和寬,并且為他們指定了Double的數(shù)據(jù)類型。輸出的結(jié)果也指定為Double類型。包裹代碼中,讓length和width相乘,得到的就是矩形的面積,用return這個關(guān)鍵字,將結(jié)果返出函數(shù)。
在函數(shù)外面,任意給這兩個參數(shù)指定某個長度值,就得到了相應(yīng)的面積。
參數(shù)還可以更靈活。
我們繼續(xù)擴(kuò)展這個函數(shù)?,F(xiàn)在,我想讓函數(shù)能計算面積的同時還能計算周長,可以這樣設(shè)計:
func rectangle(length: Double, width: Double, isPerimeter:Bool ) -> Double {
if isPerimeter {
return (length + width) * 2
} else {
return length * width
}
}
let area = rectangle(length: 10, width: 26, isPerimeter: false)
let perimeter = rectangle(length: 10, width: 26, isPerimeter: true)
print("長方形的面積是\(area),周長是\(perimeter)")
注意看,參數(shù)還能使用布爾值,包裹代碼中就可以做一個判斷,如果isPerimeter是true,我們就計算周長,否則,還是計算面積。這樣,我在下面引用函數(shù)的時候,如果想計算面積,我就將isPerimeter設(shè)置為false,想計算周長,就將這個參數(shù)設(shè)置為true。
怎么樣,短短的幾行代碼,僅僅是參數(shù)不同,就可以實現(xiàn)不同的功能。在實際應(yīng)用時,將大幅節(jié)省你的代碼量,出錯時,也容易排查到是哪里出了問題。
默認(rèn)參數(shù)
上面這個例子中,我們想求矩形的面積,仍然要指定isPerimeter: false,這樣顯得有點啰嗦,能不能直接默認(rèn)就是求面積呢?
我們可以使用默認(rèn)參數(shù):
func rectangle(length: Double, width: Double, isPerimeter: Bool = false ) -> Double {
if isPerimeter {
return (length + width) * 2
} else {
return length * width
}
}
let area = rectangle(length: 10, width: 26)
let perimeter = rectangle(length: 10, width: 26, isPerimeter: true)
在參數(shù)中,我們指定isPerimeter的默認(rèn)值是false,這樣,后面我們調(diào)用函數(shù)時,可以不用指定這個參數(shù)的值了,函數(shù)會調(diào)用默認(rèn)值。
而當(dāng)我們想修改默認(rèn)值時,只需要再次指定,這樣,默認(rèn)值會被覆蓋,使用我們調(diào)用函數(shù)時指定的新值。
返回可選型
上面這個例子中,我們還可以這樣改造。當(dāng)指定isPerimeter為true時,計算周長,而當(dāng)isPerimeter為false時,什么都不做,返回空值。
func rectangle(length: Double, width: Double, isPerimeter: Bool ) -> Double? {
if isPerimeter {
return (length + width) * 2
} else {
return nil
}
}
let area = rectangle(length: 10, width: 26, isPerimeter: false)
注意看,我們返回值加了個?,如果不加,系統(tǒng)會報錯。因為我們返回的值可能是Double型,也可能是nil型,這樣的不確定性,不就是我們之前說過的可選型嗎?所以,我們指定函數(shù)的返回值是一個Double可選型,這樣,系統(tǒng)就不會報錯了。
多返回值
如果,我想一次性得到周長和面積,又該怎么辦呢?好辦!
func rectangle(length: Double, width: Double ) -> (area: Double, perimeter: Double) {
let area = length * width
let perimeter = (length + width) * 2
return (area, perimeter)
}
let newRectangle = rectangle(length: 15, width: 20.2)
print("長方形的面積是\(newRectangle.area),周長是\(newRectangle.perimeter)")
想要從函數(shù)中返回多個值,需要借助元組。
首先,在返回類型中,我們要分別指定返回的值及其類型。使用return時,將值用元組的形式放在返回值中。最后,調(diào)用的時候,用類似調(diào)用屬性的方式.area,.perimeter調(diào)用相應(yīng)的值。
參數(shù)的標(biāo)簽
參數(shù)已經(jīng)有名稱了,比如上面的length和width。Swift仍然具有給參數(shù)名再加標(biāo)簽的功能,我們用開始最簡單的函數(shù)舉例。
func rectangle(chang length: Double, kuan width: Double) -> Double {
return length * width
}
print(rectangle(chang: 15, kuan: 20.8) ) // 312.0
看到?jīng)]有,我們在length前面加了個chang,width前面加了個kuan,這樣,我們在調(diào)用的時候,直接使用chang,kuan就行了。
我們還可以忽略標(biāo)簽:
func rectangle(_ length: Double, _ width: Double) -> Double {
return length * width
}
print(rectangle(15,20.8) ) // 312.0
使用_,意思是可以忽略標(biāo)簽,因為參數(shù)名本身就是默認(rèn)標(biāo)簽。這樣,我們在調(diào)用函數(shù)的時候,就不用指定標(biāo)簽,直接按順序賦值即可。
可變參數(shù)
在前幾個案例中,我們定義好參數(shù),在調(diào)用函數(shù)的時候,要對參數(shù)一一對應(yīng)的賦值。
然而,有些情況,我們并不能提前確定好參數(shù)的具體數(shù)量。
比如,我想實一個計算商品總價的程序,把我買的商品價格都輸入進(jìn)去,然后算總價。實際上也就是任意n個數(shù)的求和。我們可以做樣做:
func totalValue(_ items: Double...) -> Double {
var sumPrice: Double = 0
for i in items {
sumPrice += i
}
return sumPrice
}
let totalYesterday = totalValue(20.5,58.3,88.2)
let totalToday = totalValue(322.5,909.2,69.9,12.6)
分析這段代碼,首先在參數(shù)數(shù)據(jù)類型的后面加...,然后在包裹的代碼塊中,遍歷參數(shù),然后累加。
最后,在調(diào)用函數(shù)的時候,我們實際上可以輸入滿足數(shù)據(jù)類型的任意數(shù)量的參數(shù)。
輸入輸出參數(shù)
到目前位置,我們給出的參數(shù),在函數(shù)中,都是老老實實的直接使用。如果我在函數(shù)中改變參數(shù)行不行呢?答案是不行,比如參數(shù)給了a = 3,我們不能在函數(shù)中這樣改變a +=1,這樣系統(tǒng)是會報錯的,因為默認(rèn)情況下,參數(shù)是常量。
但是,Swift仍然給了我們一個渠道,可以修改參數(shù)的值,這就是輸入輸出參數(shù)??聪旅孢@個例子,我們輸入一個人的身高,但是考慮到有鞋的高度,因此我做了一個函數(shù),能夠?qū)⑸砀邷p去一個高度,再返回出來。
func person(stature: inout Double) -> Double{
stature = stature - 0.03
return stature
}
var Tom = 1.78
person(stature: &Tom)
print(Tom)
首先,我們在參數(shù)中加了一個關(guān)鍵字inout,表示這個參數(shù)是一個輸入輸出參數(shù)。(注意,可變參數(shù)不能加inout,你可以試一下。)
接著,我們在代碼塊中對參數(shù)值進(jìn)行了-0.03的操作。
在調(diào)用的時候,我先定義了一個變量:Tom的測量身高是1.78。然后調(diào)用了一下函數(shù),這個函數(shù)對stature參數(shù)進(jìn)行了修改處理。
在引用的時候,我們使用了&符號,這個類似與C語言中的指針,就是我們改的變量Tom所指向的內(nèi)存地址。產(chǎn)生實際上的效果是,函數(shù)對外部的變量值進(jìn)行了修改,因此,我們再次調(diào)用Tom的時候,就是修改過的值。
如果你嘗試像這樣直接調(diào)用函數(shù),print(person(stature: 1.78)),系統(tǒng)會提示,說字面量不可修改,因為你已經(jīng)用1.78把參數(shù)stature寫死了,需要把1.78這個位置換成可修改的變量,才能完成參數(shù)的加工修改。
小結(jié)與預(yù)告
好了,本節(jié)內(nèi)容先告一段落。
我們介紹了函數(shù)的參數(shù)和返回值的一些衍生概念。
下節(jié),我們將拓展數(shù)據(jù)類型的概念。