Function
The function has two way to affect the outside scope
- Use return value to tell the caller.
- Use the
inout
with reference to change the the original value outside.
Function Usages
Without Parameter and Return Value
func sayHello() {
print("Hello")
}
// Call the function, will print「hello」
sayHello()
With Parameter
func greet(name: String) {
print("Hello \(name)")
}
// Call the function pass the String as the input to the function, will print 「Hello Mike」
greet(name: "Mike")
With Multiple Parameter
func addTwoNum(a: Int, b: Int) {
var c = a + b
print(c)
}
// Call the function, pass two parameter to the function, will print 「11」
addTwoNum(a: 5, b: 6)
With Return Value
once defined the return type of a function, it must have a return operation when the function logic end.
func addTwoNum(a: Int, b: Int) -> Int {
var c = a + b
return c
}
// The res will be assigned as 「12」
var res = addTwoNum(a: 3, b: 9)
// The return value can be ignored.
addTwoNum(a: 4, b: 9)
With Multiple Return Value
// Return as a tuple
func getTwoNum() -> (Int, Int) {
var a = 2
var b = 4
return (a, b)
}
var nums = getTwoNum()
// Return as a optional dictionary
func getThreeNum() -> (a: Int, b: Int, c: Int)? {
var a = 2
var b = 4
var c = 3
return (a, b, c)
}
With Multiple Parameter and Multiple Return Value
func minMax(array: Int[]) -> (min: Int, max: Int)? {
if array.isEmpty {return nil}
var curMin = array[0]
var curMax = array[0]
for value in array[1.. curMax {
curMax = value
}
}
return (curMin, curMax)
}
// Use optional binding to check
if let bound = minMax(array: [3, 5, 5, 6, 22, 13, 16, 24, 11]) {
print("Min: \(bound.min)")
print("Max: \(bound.max)")
}
With Implicit Return
- It only allow the first one sentence to implicit return.
// It will return the result of a + b
func sum(a: Int, b: Int) -> Int{
a + b
}
// It will not return a value
func sum(a: Int, b: Int) {
a + b
}
// This can't work!!! It will trige compile-time error.
func getTwoNum() -> Int {
var a = 2
var b = 4
a + b
// Here not allow to implicit return value
// The implicit return only allow the first one sentence
}
// This can work, because the getTwoNum only use first one sentence to return
func get() -> (Int, Int) {
var a = 5
return (5, 6)
}
func getTwoNum() -> (Int, Int) {
get() // The implicit return can work.
}
Parameter
Parameter Names and Argument Labels
// Argument Labels
func greet(person: String, from hometown: String) -> String {
// The 'person' and 'hometown' are parameter names.
// The 'from' is a argument label of th second parameter.
return "\(person) is come from \(hometown)."
}
print(greet(person: "Mike", from: "New York"))
Omitting Argument Labels
Use the underscore to omit the label
func readFromFile(_ path: String) {
print(path)
}
readFromFile("./music/one.mp3")
Default Parameter Values
func drawRect(x: Int, y: Int, w: Int, h: Int, color: (Int, Int, Int) = (0, 0, 0)) {
// Here the color has default value (0, 0, 0)
}
Variadic Parameter
- The values passed will be made as as an array. For example, the
Double...
passed will be made as[Double]
func average(_ nums: Double...) -> Double{
var total: Double = 0
for num in nums {
total += num
}
return total / Double(nums.count)
}
print(average(3.3, 2.9, 4.6))
To make it unambiguous between the variadic parameter and normal parameters. The first parameter that comes after a variadic parameter must have an apparent argument label.
func getOne(_ nums: Double..., cut cutLen: Int) -> Double{ return 1.0 } print(getOne(3.3, 2.9, 4.6, cut: 3)) // Another way func getAnotherOne(_ nums: Double..., cutLen: Int) -> Double{ return 1.0 } print(getAnotherOne(3.3, 2.9, 4.6, cutLen: 3))
In-Out Parameters
Function parameters are constants by default.
To modify the parameter’s value and let the changes persist after the function call, we can use the inout
keyword.
(Using the inout
keyword, we can change the origin value via the function call)
The inout
value can’t have a default value, variadic parameters can’t be marked as inout
.
Without
inout
func swap(_ a: Int, _ b: Int) { var temp = a a = b // It will trigger the compile-time error. b = temp // The parameters are constant. } var x = 2 var y = 3 swap(x, y) print("x = \(x), y = \(y)"
With
inout
func swap(_ a: inout Int, _ b: inout Int) { var temp = a a = b b = temp } var x = 2 var y = 3 swap(&x, &y) // Here should use the reference sign so that the funtion can konw where to change the value of the original variable. print("x = \(x), y = \(y)") // It will print 「x = 3, y = 2」
Function Types
To describe a function’s input and output.
Such as (Int, Int) -> Int
or () -> Void
.
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
var mathFunction: (Int, Int) -> Int = addTwoInts
Function Types as Parameter Type
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
func printResult(_ mathFunc: (Int, Int) -> Int, _ a: Int, _ b: Int) {
print("Result: \(mathFunc(a, b))")
}
printResult(addTwoInts, 2, 7)
// Print 「Result: 9」
Function Types as Return Types
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}
// Return a function type
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
return backward ? stepBackward : stepForward
}
var cur = 3
let moveNearToZero = chooseStepFunction(backward: cur > 0)
// So the moveNearToZero will refers to the stepBackward() function.
while cur != 0 {
print("Cur: \(cur)")
cur = moveNearToZero(cur)
}
result:
cur: 3
cur: 2
cur: 1
Nested Function
Hidden from the outside world by default.
Only when the nested function be returned, it can be used in the caller’s scope.
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
func stepForward(input: Int) -> Int { return input + 1 }
func stepBackward(input: Int) -> Int { return input - 1 }
return backward ? stepBackward : stepForward
}
var cur = -4
let moveNearToZero = chooseStepFunction(backward: cur > 0)
// moveNearToZero now is refers tyo the nested stepForward()
cur = moveNearToZero(cur)