var str = "Hello, playground"
// 需要好好理解
/****************** 函数 Functions ********************/
/*
* 函数的定义与调用 (Defining and Calling Functions)
* 函数参数与返回值 (Function Parameters and Return Values)
* 函数参数名称 (Function Parameter Names)
* 函数类型 (Function Types)
* 嵌套函数 (Nested Functions)
*/
// 函数是用来完成特定任务的独立的代码块
// 函数的合适的名字,用来表示函数做什么,并且当函数需要执行的时候,这个名字会被用于"调用"函数
// swift统一的函数语法足够灵活,可以表示任何函数
// 参数可以提供默认值,以简化函数的调用,参数也可以既当做传入参数,也当做传出参数,也就是说一旦函数执行结束,传入的函数可以被修改
// swift中,每一个函数都有一种类型,包括函数的参数值类型
// 函数可以作为参数,可以作为返回值
/**************** 函数的定义与调用*****************/
// 你可以定义一个或多个有名字和类型的值作为函数的输入(输出参数:parameters)
// 也可以定义某种类型的值作为函数执行结束的输出,(称为返回类型return type)
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 {
return sayHelloWorld()
}
}
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")
while currentValue != 0 {
print("\(currentValue)...")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// 嵌套函数
// 以上的都是全局函数,定义在全局中
// 你也可以把函数定义在函数体里,成为嵌套函数(functions)
// 嵌套函数默认是外界不可用的,但是可以被他们的外围函数调用,一个外围函数也可以返回它的某一个嵌套函数,使得这个函数可以在其他域中被使用
// 用嵌套函数重写上面的方法
func chooseStepFunction1(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 currentValue1 = -4
let moveNearerToZero1 = chooseStepFunction1(currentValue1 > 0)
while currentValue1 != 0{
print("\(currentValue1)...")
currentValue1 = moveNearerToZero1(currentValue1)
}
print("zero!")