[Swift] Day06: Function
Function parameter external variable name
Generally, you can directly call a function without specifying the external variable name:
func helloWithName(name: String, age: Int, location: String) { println("Hello \(name). I live in \(location) too. When is your \(age + 1)th birthday?")}helloWithName("Mr. Roboto", 5, "San Francisco")
However, when the class (or structure or enumeration) is used, the external variable name (except the first one) will be automatically assigned. If you want to call it directly, an error will be reported:
class MyFunClass { func helloWithName(name: String, age: Int, location: String) { println("Hello \(name). I live in \(location) too. When is your \(age + 1)th birthday?") }}let myFunClass = MyFunClass()myFunClass.helloWithName("Mr. Roboto", 5, "San Francisco")
If you miss defining the function name in OC, you can continue to define it like this, for examplehelloWithName
In this way, the external name of the first function is hidden:
class MyFunClass { func helloWithName(name: String, age: Int, location: String) { println("Hello \(name). I live in \(location) too. When is your \(age + 1)th birthday?") }}let myFunClass = MyFunClass()myFunClass.helloWithName("Mr. Roboto", age: 5, location: "San Francisco")
If you really don't want an external variable name, you can use_
To replace:
Struct Celsius {var temperatureInCelsius: Double init (fromFahrenheit fahrenheit: Double) {temperatureInCelsius = (fahrenheit-32.0)/1.8} init (fromKelvin kelvin: Double) {sources = kelvin-273.15} init (_ celsius: Double) {temperatureInCelsius = celsius} let boilingPointOfWater = Celsius (fromFahrenheit: 212.0) // boilingPointOfWater. temperatureInCelsius is 100w.let freezingPointOfWater = Celsius (fromKelvin: 273.15) // freezingPointOfWater. temperatureInCelsius is 0.0let bodyTemperature = Celsius (37.0) // bodyTemperature. temperatureInCelsius is 37.0
Skillful Use of External Parameter names can perfectly abstract the initialization process. Let's take a look at the applications in the json-swift library.
Default parameter value
You can write the default value of the function in the function definition so that you do not need to pass this value during the call:
func add(value1 v1:Int, value2 p1:Int = 2) -> Int{ return v1 + p1}add(value1: 2, value2: 4) // 2 + 4add(value1: 1) // 1 + 2
If you do not provide an external parameter name, the default parameter name is automatically provided when the default parameter value is set.
Variable parameters
Variadic Parameters can accept more than one parameter value. For example, calculate the average:
func arithmeticMean(numbers: Double...) -> Double { var total: Double = 0 for number in numbers { // numbers is [Double] total += number } return total / Double(numbers.count)}arithmeticMean(1, 2, 3, 4, 5)arithmeticMean(3, 8, 19)
If there are more than one parameter, you must put the variable parameter at the end. Otherwise, an error is returned. It should be like this:
func sumAddValue(addValue:Int=0, numbers: Int...) -> Int { var sum = 0 for number in numbers { // numbers === [Int] sum += number + addValue } return sum}sumAddValue(addValue: 2, 2,4,5) // (2+2) + (4+2) + (5+2) = 17
Constant and variable parameters
The default parameter is a constant and cannot be changed in the function body. We canvar
You can add a new value to the function definition.var
Avoid defining new variables in the function body.
For example, this right alignment function:
func alignRight(var string: String, count: Int, pad: Character) -> String { let amountToPad = count - countElements(string) 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, 10, "-") // "-----hello"
Input/output parameters (inout)
Modifying the variable parameter in the function body does not change the parameter value itself. For example, let's look at this example:
func add(var v1:Int) -> Int { return ++v1}var a = 1add(a) // 2a // 1
If you want to use the function to modify the original valueinout
But this is incorrect:
func add(inout v1:Int) -> Int { return ++v1}var a = 1add(a) // 2a // 1
You must add&
MARK:
func add(inout v1:Int) -> Int { return ++v1}var a = 1add(&a) // 2a // 1
Generic parameter type
Here we use the example in objc. io to demonstrate the usage of generic parameter types:
// Function for exchanging two values: func valueSwap
(Inout value1: T, inout value2: T) {let oldValue1 = value1 value1 = value2 value2 = oldValue1} var name1 = "Mr. potato "var name2 =" Mr. roboto "valueSwap (& name1, & name2) // exchange string name1 // Mr. robotoname2 // Mr. potatovar number1 = 2var number2 = 5 valueSwap (& number1, & number2) // exchange the number number1 // 5number2 // 2
Function Type
In Swift, the function turned to sing and finally became a first-class citizen.
Variable
We can define a variable whose type is function:
func addTwoInts(a: Int, b: Int) -> Int { return a + b}let anotherMathFunction = addTwoIntsanotherMathFunction(1,2) // 3
Parameters
Since a function is of a type, it can also be passed as a parameter:
Func addTwoInts (a: Int, B: Int)-> Int {return a + B} func printMathResult (mathFunction: (Int, Int)-> Int, a: Int, B: int) {println ("Result: \ (mathFunction (a, B)")} printMathResult (addTwoInts, 3, 5) // PASS Parameters 2 and 3 as the parameters to the function of parameter 1
Return Value
Functions can also be returned as results. For example, if the returned value is a function whose parameter is Int and the returned value is Int, it is defined as follows:func foo() -> (Int) -> Int
. See the following example:
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} var currentValue = 3let moveNearerToZero = chooseStepFunction (currentValue> 0) // return stepForward or stepBackwardprintln ("Counting to zero:") while currentValue! = 0 {println ("\ (currentValue)...") currentValue = moveNearerToZero (currentValue)} println ("zero! ") // 3 .. // 2 .. // 1 .. // zero!
Alias
If you use more, you will find that()->
Interspersed with various()->
It is a very painful thing. We can usetypealias
Define the function alias. Its function is basically the same as typedef in OC and alias in shell. For example:
Import Foundationtypealias lotteryOutputHandler = (String, Int)-> String // This is required if no typealias is available: // func luckyNumberForName (name: String, # lotteryHandler: (String, Int) -> String)-> String {func luckyNumberForName (name: String, # lotteryHandler: lotteryOutputHandler)-> String {let luckyNumber = Int (arc4random () % 100) return teryhandler (name, luckyNumber)} luckyNumberForName ("Mr. roboto ", lotteryHandler: {name, number in return" \ (name)'s 'lucky number is \ (number) "}) // Mr. roboto's lucky number is 33
Nesting
But not all functions need to be exposed. Sometimes we define a new function to encapsulate a layer, not to reuse it. In this case, the function can be nested, for example, in the previous example:
func chooseStepFunction(backwards: Bool) -> (Int) -> Int { func stepForward(input: Int) -> Int { return input + 1 } func stepBackward(input: Int) -> Int { return input - 1 } return backwards ? stepBackward : stepForward}var currentValue = -4let moveNearerToZero = chooseStepFunction(currentValue < 0)// moveNearerToZero now refers to the nested stepForward() functionwhile currentValue != 0 { println("\(currentValue)... ") currentValue = moveNearerToZero(currentValue)}println("zero!")// -4...// -3...// -2...// -1...// zero!
Currying)
The basic idea behind keri Is that a function can be applied locally, meaning that some parameter values can be specified or bound before the function is called. This part of the function calls will return a new function.
For details, refer to the multi-faceted section of the Swift method. We can call it like this:
class MyHelloWorldClass { func helloWithName(name: String) -> String { return "hello, \(name)" }}let myHelloWorldClassInstance = MyHelloWorldClass()let helloWithNameFunc = MyHelloWorldClass.helloWithNamehelloWithNameFunc(myHelloWorldClassInstance)("Mr. Roboto")// hello, Mr. Roboto
Multiple return values
In Swift, we can use tuple to return multiple return values. For example, in the following example, the range of all numbers is returned:
func findRangeFromNumbers(numbers: Int...) -> (min: Int, max: Int) { var maxValue = numbers.reduce(Int.min, { max($0,$1) }) var minValue = numbers.reduce(Int.max, { min($0,$1) }) return (minValue, maxValue)}findRangeFromNumbers(1, 234, 555, 345, 423)// (1, 555)
The returned values may not all have values. We can also return optional results:
import Foundationfunc componentsFromUrlString(urlString: String) -> (host: String?, path: String?) { let url = NSURL(string: urlString) return (url?.host, url?.path)}let urlComponents = componentsFromUrlString("http://why/233;param?foo=1&baa=2#fragment")switch (urlComponents.host, urlComponents.path) {case let (.Some(host), .Some(path)): println("host \(host) and path \(path)")case let (.Some(host), .None): println("only host \(host)")case let (.None, .Some(path)): println("only path \(path)")case let (.None, .None): println("This is not a url!")}// "host why and path /233/param"
References
- Functions
- Swift Functions
- The diversity of Swift Methods
- Instance Methods are Curried Functions in Swift