Swift 函式(筆記)
var str = "Hello, playground"
// 需要好好理解
/****************** 函式 Functions ********************/
/*
* 函式的定義與呼叫 (Defining and Calling Functions)
* 函式引數與返回值 (Function Parameters and Return Values)
* 函式引數名稱 (Function Parameter Names)
* 函式型別 (Function Types)
* 巢狀函式 (Nested Functions)
*/
// 函式是用來完成特定任務的獨立的程式碼塊
// 函式的合適的名字,用來表示函式做什麼,並且當函式需要執行的時候,這個名字會被用於"呼叫"函式
// swift統一的函式語法足夠靈活,可以表示任何函式
// 引數可以提供預設值,以簡化函式的呼叫,引數也可以既當做傳入引數,也當做傳出引數,也就是說一旦函式執行結束,傳入的函式可以被修改
// swift中,每一個函式都有一種型別,包括函式的引數值型別
// 函式可以作為引數,可以作為返回值
/**************** 函式的定義與呼叫*****************/
// 你可以定義一個或多個有名字和型別的值作為函式的輸入(輸出引數:parameters)
// 也可以定義某種型別的值作為函式執行結束的輸出,(
func問候(大名:String)->String{
let 歡迎詞 = "歡迎你!\(大名)"
return 歡迎詞
}
print(問候("老馬"))
// 函式func開頭,定義:函式名(傳入引數名:具體引數)->返回引數
func sayHelloAgain(personName:String)->String {
return "Hello again," + personName + "!"
}
print(sayHelloAgain("Anna"))
// 函式引數和返回值(Function Parameters and Return Values)
// 函式引數在swift中極為靈活,可以任意型別的函式
// 無參函式
func sayHelloWorld()->String{
return "Hello world"
}
print(sayHelloWorld())
// 無參函式要加一個()當被呼叫的時候表示這被呼叫了
// 多引數函式(Functions With Multiple Parameters)
// 需要傳入多參的時候,用逗號分隔
func sayHello(personName:String,alreadyGreeted:Bool)->String{
if alreadyGreeted{
return sayHelloAgain(personName)
} else {
returnsayHelloWorld()
}
}
print(sayHello("Tim", alreadyGreeted: true))
// 無返回值的函式 (Functions Without Return Value)
func sayGoodbye(personName:String){
print("Goodbye,\(personName)")
}
sayGoodbye("Dave")
// 不需要返回值,就不用寫->返回值型別
// 嚴格上來說,雖然沒有返回值被定義,sayGoodbye(_:)函式返回了特殊的值,叫做Void,他其實是一個空的元組,沒有任何元素,可以寫成[]
// 被呼叫時候,一個函式的返回值可以被忽略
// 這個有點莫名其妙
func printAndCount(stringToPrint:String)->Int{
print(stringToPrint)
return stringToPrint.characters.count
}
func printWithoutCounting(stringToPrint:String){
printAndCount(stringToPrint)
}
printAndCount("hello,world")
printWithoutCounting("hello,world")
// 列印結果hello,world
// 就是第一個函式呼叫之後返回一個Int型別
// 第二個函式再呼叫第一個函式,直接列印,返回值不會被用到
// 返回值可以被忽略,但定義了有返回值的函式必須返回一個值,如果在函式定義底部沒有返回任何值,講導致編譯失敗
// 多重返回值函式(Functions with Multiple Return Values)
// 可以用元祖(tuple)型別讓多個值作為一個複合值從函式中返回
func minMax(array:[Int])->(min:Int,max:Int){
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count]{
if value < currentMin{
currentMin = value
} else if value < currentMax{
currentMax = value
}
}
return (currentMin,currentMax)
}
let bounds = minMax([8,-6,2,109,3,7])
print("min is \(bounds.min) and max is \(bounds.max)")
// 可選元組返回型別
// 如果函式返回的元組型別有可能整個元組都"沒有值",你可以使用可選的元組返回型別反映整個元組可以是nil的事實.你可以通過在元祖型別的右括號後放置一個問號來定義一個可選元祖,例如(Int,Int)?或者(String,Int,Bool)?
// 可選元祖(Int,Int)?(整個元組可選)和可選型別(Int?,Int?)(元組資料型別可選)不一樣
// 上面的程式碼就應該用可選元組,因為這個陣列很有可能為空,那麼返回就位nil
// 函式引數名稱 (Function Parameter Names)
// 函式都有外部引數和區域性引數名.
// 外部引數用於在函式呼叫時標註傳遞給函式的引數
// 區域性引數用於在函式的實現內部使用
func someFunction(firstParameterName:Int,secondParameterName:Int){
// function body goes here
// firstParameterName and secondParameterName refer to
// the argument values for the first and second parameters”
}
someFunction(1, secondParameterName: 2)
// 一般情況下,第一個引數省略其外部引數名
// 第二個以及以後的引數使用其區域性引數名作為外部引數名.
// 所有引數必須有獨一無二的區域性引數名.
// 儘管多個引數可以有相同的外部引數名,但是不同的外部引數名能讓你的程式碼更有可讀性
// 指定外部引數名
// 你可以在區域性引數名前面指定外部引數名,中間以空格分隔
func someFunction(externalParameterName localParameterName:Int){
// function body goes here, and can use localParameterName
// 函式體都在這裡,可以使用localParameterName
// to refer to the argument value for that parameter
// 引用引數的引數值
}
//someFunction(externalParameterName: <#T##Int#>)
func sayHello(to person: String,and anotherPerson:String)->String{
return "Hello \(person) and \(anotherPerson)!"
}
print(sayHello(to: "Bill", and: "Ted"))
// 為每個引數指定外部引數名,在你呼叫sayHello(to:and:)函式時兩個外部引數名都必須寫出來
// 使用外部函式名可以使函式以一種更富有表達性的類似句子的方式呼叫.並使函式體意圖清晰,更具可讀性
// 忽略外部引數名 (Omitting External Parameter Names)
// 如果你不想把第二個和以後的引數設定成外部引數,暴露你的引數給別人,你可以寫下劃線代替(_)一個明確的引數名字
func someFunction1(firstParameterName:Int,_ secondParameterName:Int){
// function body goes here
// firstParameterName and secondparameterName refer to
// the argument values for the first and second parameters
}
someFunction1(1, 2)
// 預設引數值 Default Parameter Values
// 你可以在函式體中為每個引數定義預設值(Deafult Values).當預設值被定義後,呼叫這個函式時可以忽略這個引數
func someFunction2(parameterWithDefault:Int = 12){
// function body goes here
// if no arguments are passed to the function call,
// value of parameterWithDefault is 12
}
someFunction2() // parameterWithDefault is 12
someFunction2(6) // paraneterWithDefault is 6
// 講帶有預設值的引數放在函式列表的最後,這樣可以保證在呼叫函式時,非預設引數的順序是一致的,同時使得相同的函式再不同的情況下呼叫時顯得更為清晰
// 可變引數 (variadic parameter)
// 一個可變引數可以接受零個或多個值,函式呼叫時,你可以用可變引數來制定函式引數可以被傳入不確定數量的輸入值.
// 通過在變數型別名後面加入(...)的方式來定義可變引數
// 可變引數的傳入值在函式體中變為此型別的一個數組
// 如: 一個叫numbers的Double...型可變引數,在函式體內可以當做一個numbers的[Double]型的陣列常量
// 計算算術平均數 (arithmetic mean)
func arithmeticMean(numbers:Double...) -> Double{
var total:Double = 0
for number in numbers{
total += number
}
return total/Double(numbers.count)
}
arithmeticMean(1,2,3,4,5)
arithmeticMean(2,3.2,3.1,5.3)
// 注意: 一個函式只能有一個可變引數
// 如果一個函式有很多帶預設值的引數,還有一個可變引數,那麼把可變引數放到函式的最後
// 常量引數和變數引數 (Constant and Variable Parameters)
// 函式引數預設是常量,檢視在函式體中更改引數值會導致編譯報錯.
// 如果想改,寫成變數引數.前面加 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: "-")
// 注意: 對變數引數進行修改在函式呼叫結束之後就消失了,並且對於函式體外是不可見的,變數引數僅僅存在於函式呼叫的生命週期中
// 輸入輸出引數 (In-Out Parameters)
// 變數引數,僅僅能再函式體內被更改.如果你想要一個函式可以修改引數的值,並且想要在函式呼叫結束後仍然存在,那麼就應該把這個引數定義為輸入輸出函式
// 定義一個輸入輸出引數時,在引數定義前加inout關鍵字. 一個輸入輸出引數有傳入函式的值,這個值可以被函式修改,然後被傳出函式,替換原來的值.
// 你只能傳遞變數給輸入輸出引數.不能傳入常量或者字面量(literal value)
// 當傳入的引數作為輸入輸出引數時,需要再引數前加&符,表示這個值可以被函式修改
// 注意: 輸入輸出函式不能有預設值,而且可變引數不能用inout標記.如果你用inout標記一個引數,這個引數不能被var或者let標記
func swapTwoInts(inout a:Int,inout _ b:Int){
let tempararyA = a
a = b
b = tempararyA
}
var a = 20
var b = 30
swapTwoInts(&a, &b)
print("a == \(a), b == \(b)")
// 輸入輸出引數跟返回值是不一樣的,上面這個函式根本就沒有返回值,但是也實現了值的互換.輸入輸出引數是函式對函式體外產生影響的另一種方式
// 這個屌
// 函式型別
// 每個函式都有一個特定的函式型別,由函式的引數型別和返回型別組成
func addTwoInts(a:Int,_ b:Int)->Int{
return a + b
}
func multiplyTwoInts(a:Int,_ b:Int)->Int{
return a * b
}
// 這兩個函式就是(Int,Int)->Int
// 這個函式有兩個Int型的引數返回一個int型的值
// 例子二
func printHelloWorld(){
print("hello,world")
}
// 這個函式的型別是()->void
// 使用函式型別 (Using Function Types)
var mathFunction:(Int,Int)->Int = addTwoInts
// 定義一個叫mathFunction的變數,型別為兩個Int型的引數並返回一個int型的值的函式,並將這個新變數指向addTwoInt函式
// mathFunction 和 addTwoInts有同樣的型別,所以這個賦值過程在swift型別檢查中是允許的.
// 現在,可以用mathFunction來呼叫被賦值的函數了:
mathFunction(2,3)
print("Result:\(mathFunction(2,3))")
// 有相同匹配型別的不同函式可以被賦值給同一個變數,就像非函式型別的變數一樣
mathFunction = multiplyTwoInts
print("Result:\(mathFunction(2,3))")
// 就像其他型別一樣,當賦值一個函式給常量或者變數時,你可以讓swift來推斷其函式型別:
let anotherMathFunction = addTwoInts
// 函式型別作為引數型別
// 你可以用(Int,Int)->Int這樣的函式型別作為另一個函式的引數型別,這樣你可以將函式的一部分實現留給函式的呼叫者來提供
func pringMathResulet(mathFunction:(Int,Int)->Int,_ a:Int,_ b:Int){
print("Result:\(mathFunction(a,b))")
}
pringMathResulet(addTwoInts, 3, 5)
// 傳入3和5,然後呼叫addTwoInts的方法
// 函式型別為返回型別
// 你可以用函式型別作為另一個函式的返回型別,你需要做的是在返回剪頭(->)後寫一個完整的函式型別
func stepForward(input:Int)->Int{
return input + 1
}
func stepBackward(input:Int)->Int{
return input - 1
}
func chooseStepFunction(backwards:Bool)->(Int)->Int{
return backwards ? stepBackward : stepForward
}
// 返回型別是(int)->int型別的函式
var currentValue = 3
let moveNearerToZero = chooseStepFunction(currentValue > 0)
print("Counting to zero")
whilecurrentValue != 0 {
print("\(currentValue)...")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// 巢狀函式
// 以上的都是全域性函式,定義在全域性中
// 你也可以把函式定義在函式體裡,成為巢狀函式(functions)
// 巢狀函式預設是外界不可用的,但是可以被他們的外圍函式呼叫,一個外圍函式也可以返回它的某一個巢狀函式,使得這個函式可以在其他域中被使用
// 用巢狀函式重寫上面的方法
func chooseStepFunction1(backwards:Bool)->(Int)->Int{
func stepForward(input:Int)->Int{return input + 1}