Swift和Java在函数(method/方法)方面的比较
1. 函数是用来完成特定任务的独立的代码块。Swift中函数的使用比Java中更灵活,在 Swift 中,可以把函数当做别的函数的参数,也可以从其他函数中返回函数。函数的定义可以写在在其他函数定义中,这样可以在嵌套函数范围内实现功能封装。在函数的参数值类型和返回值类型方面,Swift和Java函数的用法是相似的。
2. 函数的申明和调用
Swift:
func sayHelloAgain(personName: String) -> String { return "Hello again, " + personName + "!" } print(sayHelloAgain("Anna")) // prints "Hello again, Anna!"
函数以 func
作为前缀。指定函数返回类型时,用返回箭头 ->
(一个连字符后跟一个右尖括号)后跟返回类型的名称的方式来表示。
Java:
public String sayHello(String personName){ return "hello, "+personName; } System.out.println(sayHello("morden"));
3. 函数参数与返回值(Function Parameters and Return Values)
3.1 多重输入参数(Multiple Input Parameters)
Swift:
func halfOpenRangeLength(start:Int, end:Int)->Int{ return end - start }
Java:
public int halfOpenRangeLength(int start, int end){ return end - start; }
3.2 无参函数(Functions Without Parameters)
Swift:
func sayHelloWorld()->String{ return "hello world" }
Java:
public String sayHelloWorld(){ return "hello world"; }
3.3 无返回值函数(Functions Without Return Values)
Swift:
func sayGoodbye(personName:String){ print("GoodBye, \(personName)") }
Java:
public void sayGoodbye(String personName){ System.out.println("Goodbye, "+personName); }
注意:在返回值方面,Swift比Java语法灵活多了,看下面代码
func printAndCount(stringToPrint: String) -> Int { print(stringToPrint) return stringToPrint.characters.count } func printWithoutCounting(stringToPrint: String) { printAndCount(stringToPrint) } printAndCount("hello, world") // prints "hello, world" and returns a value of 12 printWithoutCounting("hello, world") // prints "hello, world" but does not return a value
第一个函数 printAndCount
,输出一个字符串并返回 Int
类型的字符数。第二个函数printWithoutCounting
调用了第一个函数,但是忽略了它的返回值。
3.4 多重返回值函数(Functions with Multiple Return Values)
func count(string: String) -> (vowels: Int, consonants: Int, others: Int) { var vowels = 0, consonants = 0, others = 0 for character in string.characters { switch String(character).lowercaseString { case "a", "e", "i", "o", "u": ++vowels case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z": ++consonants default: ++others } } return (vowels, consonants, others) }
这个例子中,count
函数用来计算一个字符串中元音,辅音和其他字母的个数(基于美式英语的标准)。
let total = count("some arbitrary string!") print("\(total.vowels) vowels and \(total.consonants) consonants") // prints "6 vowels and 13 consonants"
4. 外部参数名(External Parameter Names)
如果你希望函数的使用者在调用函数时提供参数名字,那就需要给每个参数除了局部参数名外再定义一个外部参数名
。外部参数名写在局部参数名之前,用空格分隔。外部参数名函数格式如下:
func someFunction(externalParameterName localParameterName: Int) { // function body goes here, and can use localParameterName // to refer to the argument value for that parameter }
Swift代码如下:
func join(string s1 : String, toString s2 : String, withJoiner joiner: String)->String{ return s1 + joiner + s2 }
//调用函数 let temp = join(string: "hello", toString: "world", withJoiner: ", ") print(temp)
默认参数值(Default Parameter Values).你可以在函数体中为每个参数定义默认值
。当默认值被定义后,调用这个函数时可以忽略这个参数。代码如下:
func join(string s1: String, toString s2: String, withJoiner joiner: String = " ") -> String { return s1 + joiner + s2 }
像第一个版本的 join
函数一样,如果 joiner
被赋值时,函数将使用这个字符串值来连接两个字符串:
join(string: "hello", toString: "world", withJoiner: "-") // returns "hello-world"
当这个函数被调用时,如果 joiner
的值没有被指定,函数会使用默认值(" "):
join(string: "hello", toString:"world") // returns "hello world"
5. 可变参数(Variadic Parameters)
一个可变参数(variadic parameter)
可以接受一个或多个值。函数调用时,你可以用可变参数来传入不确定数量的输入参数。通过在变量类型名后面加入(...)
的方式来定义可变参数。传入可变参数的值在函数体内当做这个类型的一个数组。代码如下:
func arithmeticMean(numbers:Double...){ var total : Double = 0 for item in numbers{ total += item } print("total is \(total)") } arithmeticMean(1, 2, 3, 4, 5) // returns 3.0, which is the arithmetic mean of these five numbers arithmeticMean(3, 8, 19) // returns 10.0, which is the arithmetic mean of these three numbers
注意:一个函数至多能有一个可变参数,而且它必须是参数表中最后的一个。这样做是为了避免函数调用时出现歧义。如果函数有一个或多个带默认值的参数,而且还有一个可变参数,那么把可变参数放在参数表的最后。
6.
常量参数和变量参数(Constant and Variable Parameters)
函数参数默认是常量。试图在函数体中更改参数值将会导致编译错误。这意味着你不能错误地更改参数值。但是,有时候,如果函数中有传入参数的变量值副本将是很有用的。你可以通过指定一个或多个参数为变量参数,从而避免自己在函数中定义新的变量。变量参数不是常量,你可以在函数中把它当做新的可修改副本来使用。通过在参数名前加关键字 var
来定义变量参数:
func alignRight(var string : String, count : Int, pad : Character)->String{ let amountToPad = count - 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, 10, "-") // paddedString is equal to "-----hello" // originalString is still equal to "hello"
注意: 对变量参数所进行的修改在函数调用结束后便消失了,并且对于函数体外是不可见的。变量参数仅仅存在于函数调用的生命周期中。
7. 输入输出参数(In-Out Parameters)
变量参数,仅仅能在函数体内被更改。如果你想要一个函数可以修改参数的值,并且想要在这些修改在函数调用结束后仍然存在,那么就应该把这个参数定义为输入输出参数(In-Out Parameters)。定义一个输入输出参数时,在参数定义前加 inout
关键字。一个输入输出参数有传入函数的值,这个值被函数修改,然后被传出函数,替换原来的值。你只能将变量作为输入输出参数。你不能传入常量或者字面量(literal value),因为这些量是不能被修改的。当传入的参数作为输入输出参数时,需要在参数前加&
符,表示这个值可以被函数修改。注意: 输入输出参数不能有默认值,而且可变参数不能用 inout
标记。如果你用 inout
标记一个参数,这个参数不能被 var
者 let
标记。
func swapTwoInts(inout a: Int, inout b: Int) { let temporaryA = a a = b b = temporaryA }
我们可以用两个 Int
型的变量来调用 swapTwoInts
。需要注意的是,someInt
和 anotherInt
在传入swapTwoInts
函数前,都加了 &
的前缀,代码如下:
var someInt = 3 var anotherInt = 107 swapTwoInts(&someInt, &anotherInt) print("someInt is now \(someInt), and anotherInt is now \(anotherInt)") // prints "someInt is now 107, and anotherInt is now 3”
从上面这个例子中,我们可以看到 someInt
和 anotherInt
的原始值在 swapTwoInts
函数中被修改,尽管它们的定义在函数体外。注意: 输入输出参数和返回值是不一样的。上面的 swapTwoInts
函数并没有定义任何返回值,但仍然修改了 someInt
和 anotherInt
的值。输入输出参数是函数对函数体外产生影响的另一种方式。
8. 函数类型(Function Types
函数类型(Function Types:每个函数都有种特定的函数类型,由函数的参数类型和返回类型组成。
8.1 申明函数类型,代码如下:
func addTwoInts(a: Int, b: Int) -> Int { return a + b } func multiplyTwoInts(a: Int, b: Int) -> Int { return a * b }
8.2 使用函数类型(Using Function Types),代码如下:
var mathFunction: (Int, Int) -> Int = addTwoInts print("Result: \(mathFunction(2, 3))") // prints "Result: 5" mathFunction = multiplyTwoInts print("Result: \(mathFunction(2, 3))") // prints "Result: 6"
8.3 函数类型作为参数类型(Function Types as Parameter Types):你可以用(Int, Int) -> Int
这样的函数类型作为另一个函数的参数类型。这样你可以将函数的一部分实现交由给函数的调用者。代码如下:
func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) { print("Result: \(mathFunction(a, b))") } printMathResult(addTwoInts, 3, 5) // prints "Result: 8”
8.4 函数类型作为返回类型(Function Type as Return Types)
我们可以用函数类型作为另一个函数的返回类型。需要做的是在返回箭头(->
)后写一个完整的函数类型。下面的这个例子中定义了两个简单函数,分别是 stepForward
和stepBackward
。stepForward
函数返回一个比输入值大一的值。stepBackward
函数返回一个比输入值小一的值。这两个函数的类型都是 (Int) -> Int
:代码如下:
func stepForward(input: Int) -> Int { return input + 1 } func stepBackward(input: Int) -> Int { return input - 1 }
chooseStepFunction
根据布尔值 backwards
来返回 stepForward
函数或 stepBackward
函数:代码如下:
func chooseStepFunction(backwards: Bool) -> (Int) -> Int { return backwards ? stepBackward : stepForward }
现在可以用 chooseStepFunction
来获得一个函数,不管是那个方向:
var currentValue = 3 let moveNearerToZero = chooseStepFunction(currentValue > 0) // moveNearerToZero now refers to the stepBackward() function
这个例子中计算出从 currentValue
逐渐接近到0
是需要向正数走还是向负数走。currentValue
的初始值是3
,这意味着 currentValue > 0
是真的(true
),这将使得 chooseStepFunction
返回stepBackward
函数。一个指向返回的函数的引用保存在了 moveNearerToZero
常量中。
8.5 嵌套函数(Nested Functions)
你所见到的所有函数都叫全局函数(global functions),它们定义在全局域中。你也可以把函数定义在别的函数体中,称作嵌套函数(nested functions)。默认情况下,嵌套函数是对外界不可见的,但是可以被他们封闭函数(enclosing function)来调用。一个封闭函数也可以返回它的某一个嵌套函数,使得这个函数可以在其他域中被使用。你可以用返回嵌套函数的方式重写 chooseStepFunction
函数:
func chooseStepFunction(backwards: Bool) -> (Int) -> Int { func stepForward(input: Int) -> Int { return input + 1 } func stepBackward(input: Int) -> Int { return input - 1 } return backwards ? stepForward : stepBackward } @IBAction func Test(sender: AnyObject) { var currentValue = -4 let moveNearerToZero = chooseStepFunction(currentValue < 0) // moveNearerToZero now refers to the nested stepForward() function while currentValue != 0 { print("\(currentValue)... ") currentValue = moveNearerToZero(currentValue) } }
// -4...
// -3...
// -2...
// -1...