//函數(shù)的定義
//形參默認(rèn)是let,也只能是let
import Foundation
func pi() -> Double {
return 3.14
}
func sum(v1: Int, v2: Int) -> Int {
return v1+v2
}
//無返回值
func sayHello() -> Void {
print("Hello")
}
func sayHello1() -> () {
print("Hello")
}
func sayHello2() {
print("Hello")
}
//隱式返回 (Implicit Return)
//如果整個函數(shù)式一個單一表達式,那么函數(shù)會隱式返回這個表達式
func sum(v1: Int, v2: Int) {
v1+v2
}
print("sum is (sum(v1: 10, v2: 20))")
//返回元組:實現(xiàn)多值返回
func calculate(v1: Int, v2: Int) -> (sum: Int, difference: Int, average: Int) {
let sum = v1 + v2
return(sum, v1-v2, sum >> 1)
}
let result = calculate(v1: 10, v2: 20)
print(result.sum)
print(result.difference)
print(result.average)
//函數(shù)的文檔注釋
/// 求和【概述】
///
///將兩個整數(shù)相加【更詳細(xì)的描述】
///
/// - Parameter v1: 第一個整數(shù)
/// - Parameter v2: 第二個整數(shù)
/// - Returns: 2個整數(shù)的和
///
/// - Note: 傳入2個整數(shù)即可【批注】
///
func sum2(v1: Int, v2: Int) ->Int { v1 + v2}
//更加詳細(xì)的文檔參考:https://swift.org/documentation/api-design-guidelines
//參數(shù)標(biāo)簽(Argument Label)
func goToWork (at time: String) {
print("this time is (time)")
}
goToWork(at: "8:20") //this time is 8:20
//可以使用下劃線_ 省略參數(shù)標(biāo)簽
func sum(_ v1: Int, _ v2: Int) -> Int {
v1 + v2
}
print(sum(10, 20)) //30
//默認(rèn)參數(shù)值
//函數(shù)可以有默認(rèn)值(Default Parameter Value)
func check(name: String = "nobody", age: Int, job: String = "none") {
print("name=(name), age=(age), job=(job)")
}
check(name: "Jack", age: 20, job: "Doctor") //name=Jack, age=20, job=Doctor
check(name: "Rose", age: 19) //name=Rose, age=19, job=none
check(age: 10, job: "Batman") //name=nobody, age=10, job=Batman
check(age: 15) //name=nobody, age=15, job=none
//C++的默認(rèn)參數(shù)值有個限制:必須從右往左設(shè)置。由于Swift擁有參數(shù)標(biāo)簽,因此并沒有此類限制
//但是再省略參數(shù)標(biāo)簽時,需要特別注意,避免出錯
//這里的middle不可以省略參數(shù)標(biāo)簽
func test(_ first: Int = 10, middle: Int, _ last: Int = 30) {}
test(middle:20)
//可變參數(shù)(Variadic Parameter)
func sum1(_ numbers: Int...) -> Int {
var total = 0
for number in numbers {
total += number
}
return total
}
print("sum1 is (sum1(10, 20, 30, 40))"); // sum1 is 100
//一個函數(shù)最多只能有1個可變參數(shù)
//緊跟在可變參數(shù)后面的參數(shù)不能加省略參數(shù)標(biāo)簽 “”
func test( numbers: Int..., string: String, _ other: String) {}
test(10, 20, 30, string: "jack", "other")
/// - Parameters:
/// - items: Zero or more items to print. (可變參數(shù))
/// - separator: A string to print between each item. The default is a single
/// space (" "). (分隔符,默認(rèn)空格)
/// - terminator: The string to print after all items have been printed. The
/// default is a newline ("\n"). (結(jié)束符,默認(rèn)換行符)
/// public func print(_ items: Any..., separator: String = " ", terminator: String = "\n")
print("1", "2", "3", separator:",") //1,2,3#
print("1", "2", "3", "4", "5", separator: "_") //1_2_3_4_5
print("my name is Jake.", terminator: "")
print("my age is 18.") //my name is Jake.my age is 18.
var number1 = 10
//函數(shù)參數(shù)默認(rèn)都是let常量,聲明為var也不行,不能時變量,不可以改
func add(_ num: Int) {
// num += 1 //這里回報錯,先注釋掉了
}
add(number1) //這僅僅是把 10 值傳遞給了add方法,和number1這個變量并沒有關(guān)系
//輸入輸出參數(shù)(Int-Out Parameter)
//可以用inout定義一個輸入輸出參數(shù):在函數(shù)內(nèi)部修改外部實參的值,注意可變參數(shù)不能標(biāo)記為inout
func add1(_ num: inout Int) {
num = 20
}
add1(&number1)
print(number1) //20
func swapValues(_ v1: inout Int, _ v2: inout Int) {
let tmp = v1
v1 = v2
v2 = tmp
}
var num1 = 10
var num2 = 20
swapValues(&num1, &num2)
//利用元組來實現(xiàn)交換值
func swapValues2(_ v1: inout Int, _ v2: inout Int) {
(v1, v2) = (v2, v1)
}
// 匯編中
// callq為調(diào)用方法,后面跟著函數(shù)方法地址,例如:callq 0x100000f60
// leaq用來傳地址,例如:leaq 0x10da(%rip), %rdi 所代表的意思是把0x10da(%rip)這個地址值,傳給%rdi寄存器
// movq $0x14, (%rdi) 匯編代碼含義如下:
// 把20這個值,復(fù)制給(%rdi)所對應(yīng)的內(nèi)存空間
// (%rdi) 代表的意思是,找到rdi寄存器存儲到地址值所對應(yīng)的內(nèi)存空間
var number = 10;
func test(_ num: inout Int) {
num = 20
}
test(&number) //本質(zhì)上還是地址傳遞,把地址傳給方法test,在函數(shù)內(nèi)部把值賦值到內(nèi)存地址,匯編代碼為 leaq 開頭
//test(number) //這種就是值傳遞,匯編代碼為 movq 開頭,例如:movq -0x30(%rbp), %rdi 所代表的意思是把%rbp減去-0x30結(jié)果的內(nèi)存地址中的值,賦值給%rdi寄存器存儲的內(nèi)存地址所指向的內(nèi)存。
print(number)
//inout參數(shù)不能有默認(rèn)值
//inout參數(shù)的本質(zhì)是地址傳遞(引用傳遞)
//inout參數(shù)只能傳入可以被多次賦值的
//函數(shù)重載 (Function Overload)
//規(guī)則
//參數(shù)名相同
//參數(shù)個數(shù)不同 || 參數(shù)類型不同 || 參數(shù)標(biāo)簽不同
func sum1(v1: Int, v2: Int) -> Int {
v1 + v2
}
func sum1(v1: Int, v2: Int, v3: Int) -> Int {
v1 + v2 + v3
} //參數(shù)個數(shù)不同
func sum1(v1: Int, v2: Double) -> Double {
Double(v1) + v2
} //參數(shù)類型不同
func sum1(v1: Double, v2: Int) -> Double {
v1 + Double(v2)
} //參數(shù)類型不同
func sum1(_ v1: Int, _ v2: Int) -> Int {
v1 + v2
} //參數(shù)標(biāo)簽不同
func sum1(a: Int, b: Int) -> Int {
a + b
} //參數(shù)標(biāo)簽不同
print(sum1(v1: 10, v2: 20)) //30
print(sum1(v1: 10, v2: 20, v3: 30)) //60
print(sum1(v1: 10, v2: 20.0)) //30.0
print(sum1(v1: 10.0, v2: 20)) //30.0
//print(sum1(10, 20)) 這種在新版swift中不可以了,有歧義報錯
print(sum1(a:10, b:20)) //30
//函數(shù)重載注意點
//返回值類型與函數(shù)重載無關(guān), 參數(shù)相同,參數(shù)類型相同,但是返回值不同,不構(gòu)成重載
func sum3(v1: Int, v2: Int) -> Int {v1 + v2}
func sum3(v1: Int, v2: Int) {}
//sum3(v1:10, v2:20)
//默認(rèn)參數(shù)值和函數(shù)重載一起使用產(chǎn)生二義性時,編譯器并不會報錯(在c++中回報錯)
func sum4(v1: Int, v2: Int) -> Int {
v1 + v2
}
func sum4(v1: Int, v2: Int, v3: Int = 10) -> Int {
v1 + v2 + v3
}
//會調(diào)用sum(v1: Int, v2: Int)
print("sum4 (sum4(v1: 10, v2: 20))")
//可變參數(shù),省略參數(shù)標(biāo)簽,函數(shù)重載一起使用產(chǎn)生二義性時,編譯器有可能會報錯
//func sum5(v1: Int, v2: Int) -> Int { //注銷掉這個函數(shù)就可以編譯通過
// v1 + v2
//}
func sum5(_ v1: Int, _ v2: Int) -> Int {
v1 + v2
}
func sum5(_ numbers: Int...) -> Int {
var total = 0
for number in numbers {
total += number
}
return total
}
sum5(10, 20)
//內(nèi)聯(lián)函數(shù) (Inline Function)
//如果開啟了編譯器優(yōu)化(Release模式默認(rèn)會開啟優(yōu)化),編譯器會編譯時自動將某些函數(shù)變成內(nèi)聯(lián)函數(shù)
//將函數(shù)調(diào)用展開成函數(shù)體
//開啟步驟:Build Setting -> Swift Compiler-Code Generation -> Optimization Level(優(yōu)化等級)。 debug模式下默認(rèn)不優(yōu)化
//例如
func test(){
print("test")
}
//會把上述函數(shù)直接展開成如下, 減少函數(shù)調(diào)用開銷,例如開辟??臻g,回收??臻g 等
print("test")
//有一些函數(shù)不會被內(nèi)聯(lián):
// 1.函數(shù)體比較長
// 2.包含遞歸調(diào)用
// 3.包含動態(tài)派發(fā) (例如多態(tài)調(diào)用類方法,在運行時才能確定調(diào)用方法,這種就不會被內(nèi)聯(lián))
class Person {
func test() {}
}
//關(guān)鍵字 @inline(never) 永遠(yuǎn)不會被內(nèi)聯(lián)(即使開啟了編譯器優(yōu)化),
@inline(never) func test10() {
print("test")
}
//關(guān)鍵字 @inline(_always) 開啟編譯器優(yōu)化后,即使代碼會很長,也會被內(nèi)聯(lián)(遞歸調(diào)用函數(shù),動態(tài)派發(fā)的函數(shù)除外)
//在Release模式下,編譯器已經(jīng)開啟優(yōu)化,會自動決定哪些函數(shù)需要內(nèi)聯(lián),因此沒必要使用 @inline
@inline(__always) func text11() {
print("test11")
}
class Student : Person {
override func test() {}
}
class Teacher : Person {
override func test() {}
}
var p: Person = Student();
p = Teacher();
p.test()
//函數(shù)類型
//每一個函數(shù)都是有類型的,函數(shù)類型由形式參數(shù)類型,返回值類型組成
func test2() {}
func sum2(a: Int, b: Int){ a+b }
// 定義變量
var fn: (Int, Int) -> Int = sum2
fn(2, 3) //5, 調(diào)用時不需要參數(shù)標(biāo)簽
//函數(shù)類型作為函數(shù)參數(shù)
func sum5test(v1: Int, v2: Int) -> Int {
v1 + v2
}
func difference1(v1: Int, v2: Int) -> Int {
v1 - v2
}
func printResult(_ mathFn: (Int, Int) -> Int, _ a: Int, _ b: Int) {
print("Result: (mathFn(a,b))")
}
printResult(sum5test, 5, 2)
printResult(difference1, 5, 2)
//class Person2 {
// var age: Int = 0
// var fn: (_ a: Int, _ b: Int) -> Int {
// return a+b
// }
//}
//函數(shù)類型作為函數(shù)返回值
//返回值時函數(shù)類型的函數(shù),叫做高階函數(shù)(Higher-Order Function),例如下面的forward為高階函數(shù)
func next(_ input: Int) -> Int {
input + 1
}
func previous(_ input: Int) -> Int {
input - 1
}
func forward(_ forward: Bool) -> (Int) -> Int {
forward ? next : previous
}
print(forward(true)(3)) //4
print(forward(false)(3)) //2
//typealias
//typealias用來給類型起別名
typealias Byte = Int8
typealias Short = Int16
typealias Long = Int64
//給元組類型起別名,Date代表右邊的元組
typealias Date = (year: Int, month: Int, day: Int)
func test9(_ date: Date) {
print(date.0)
print(date.year)
}
test9((2011, 9, 10)) // 2011, 2011
//
typealias IntFn = (Int, Int) -> Int
func difference(v1: Int, v2: Int) -> Int {
v1 - v2
}
let fn1: IntFn = difference
print(fn1(20, 10)) //10
//要求參數(shù)時IntFn類型,difference是符合這種類型的,所以可以傳入
func setFn(_ fn: IntFn) {}
setFn(difference)
//返回類型是IntFn
func getFn()-> IntFn { difference }
//按照Swift標(biāo)準(zhǔn)庫的定義,Void就是空元組()
func testVoid() {}
func testVoid1() -> Void {}
func testVoid2() -> () {}
//按照Swift標(biāo)準(zhǔn)庫的定義,Void就是空元組(), 下面是源碼
public typealias Void = ()
//嵌套函數(shù)(Nested Function)
//將函數(shù)定義在函數(shù)內(nèi)部
func forward1(_ forward: Bool) -> (Int) -> Int {
func next(_ input: Int) -> Int {
input + 1
}
func previous(_ input: Int) -> Int {
input - 1
}
return forward ? next : previous
}
forward1(true)(3) //4
forward1(false)(3) //2