函数
/*
函数分为函数名,参数,返回值,执行代码块四部分
有返回值函数可以作为一个值直接在print里输出
*/
//函数定义
func max(a:Int, b:Int, c:Int) -> Int
{
return 1
}
max(1, b: 2, c: 3)
func firstMethod(str:String) ->String
{
return "123"
}
print(firstMethod("123"))
//没有返回值的函数
func noReturn(str:String)
{
print("no return")
}
//多个返回值的函数
func mutableReturn(str:String) ->(String, String)
{
return ("1", "2")
}
func mutableReturnWithName() ->(height:Int, weight:Int)
{
return (1, 2)
}
var man = mutableReturnWithName()
print(man.height)
//函数调用本身 也就是递归
func doAgain(num:Int) -> String
{
if num > 5{
print("000")
return "(doAgain(num - 1))"
}else{
return "fff"
}
}
print(doAgain(10))
/*
递归是非常有用的,例如程序希望遍历某个路径下的所有文件,但这个路径下的文件夹的深度是未知的,那就可以使用递归来实现这个需求。系统可以设定一个函数,改函数接受一个文件路径作为参数,该参数可遍历出当前路径下的所有文件和文件路径--该函数再次调用函数本身来处理该路径下的所有文件路径
*/
/*
函数的参数
第一个参数如果不写外部参数,是不会显示外部参数的,第二个和之后的参数如果不写外部参数,会自动默认外部参数和内部参数同名
也就是说,除了第一个参数,其他的参数就算不设置外部参数也会有外部参数
*/
//拥有外部参数名的函数
func haveWaiName(wainame neiname:String) ->String
{
print(neiname)
return "(neiname)"
}
print(haveWaiName(wainame: "name"))
//外部形参名和内部形参名一样的函数
func havesameName(name name:String) ->String
{
return name
}
print(havesameName(name: "sarah"))
//只有一部分形参有外部形参名的函数
func justSomehavename(name name:String, years:Int) -> (String, Int)
{
return (name, years)
}
print(justSomehavename(name: "marry", years: 10).0)
//形参有默认值的函数 一般将带有默认值的形参放在最后面,下面这个并不是一个好的编程习惯
func valueAlready(user name:String = "marry", msg:String)
{
print("(name),(msg)")
}
valueAlready(msg: "hi")
valueAlready(user: "tom", msg: "hi")
//参数个数可变的函数
func varibleValue(a:Int, books:String..., name:String)
{
for tmp in books
{
print(tmp)
}
}
varibleValue(3, books: "java","swift", name: "string")
/*
数量可变的参数的本质是一个数组参数,在执行代码块中当做一个数组来使用
*/
/*
函数中的形参默认是常量,如果想要变量的形参,需要自己声明
*/
func mutableNum(var name:String) ->String
{
name = name + "sss"
return name
}
print(mutableNum("mother"))
/*
在函数中,传入的参数如果是值类型,则传进去的是该值的副本,在函数中不会对原来的值产生影响
如果想要在函数中对该值进行改变,可以使用inout标签来标注
*/
func inoutFunc(inout age:Int) ->Int
{
age = age + 1
return age
}
var age = 5
print(age)//5
print(inoutFunc(&age))//6
print(age)//6
/*
当参数是引用类型的时候,程序会赋值引用的副本,不会复制该引用指向的对象
所以,当参数是引用类型的时候,即使不适用inout标签,该值仍然会在函数中被修改
但是,如果在函数中将引用类型置为空,只会切断副本和指向对象之间的联系,在函数之外,该值仍然不为空
*/
class DataWrap
{
var a:Int = 0
var b:Int = 0
}
func swap(var dw:DataWrap!)
{
var tmp = dw.a
dw.a = dw.b
dw.b = tmp
tmp = 0
dw = nil
}
var wp:DataWrap! = DataWrap()
print(wp)
swap(wp)
print(wp)//wp没有被置为空,但是如果使用了inout标签,这里就会出错
//定义一个函数变量
var myfun : (Int, Int) ->Int //这里最好不要给参数命名,虽然也可以命名,但是在使用的时候系统不会提示
var test : (String) ->Void
func pow(base base:Int, exponent:Int) ->Int
{
var result = 1
for _ in 1...exponent
{
result *= base
}
return result
}
//将pow函数赋值给mufun,则myfun可以当成pow使用
myfun = pow
print(myfun(3,4))
/*
只要被赋值的函数类型与myfun的变量类型一致,程序就可以赋值成功
通过使用函数类型的变量,可以让myfun在不同的时间指向不同的函数,从而让程序更加灵活。
*/
//其中一个参数是函数的函数
func map(var data data:[Int],fn:(Int) ->Int) ->[Int]
{
for var i = 0, len = data.count; i<len ;i++
{
data[i] = fn(data[i])
}
return data
}
func square(val:Int) ->Int
{
return val*val
}
func cube(val:Int) ->Int
{
return val*val*val
}
var data = [1,2,3]
print(map(data: data, fn: square))
print(map(data: data, fn: cube))
//这种方式可以动态的改变一个函数中的部分代码块,类似于c中的函数指针
//返回值为函数的函数
func getMathFunc(type type:String) -> (Int) ->Int
{
switch(type)
{
case "square":
return square
default:
return cube
}
}
var mathFunc = getMathFunc(type: "cube")
print(mathFunc(5))
/*
函数重载
函数名相同,但是参数个数不同或外部参数名称不同或返回值不同
这种情况就是重载
*/
/*
嵌套函数
在swift中,函数和类享有同样的级别,函数可以直接声明在文件里,而不用单独声明在一个类里
所以,函数可以当成变量被引用,被返回,在函数中声明函数
*/
func getMathFunc2(type type:String) ->(Int) ->Int
{
func square(val: Int) ->Int
{
return val*val
}
func cube(val:Int) ->Int
{
return val*val*val
}
switch(type)
{
case "square":
return square
default:
return cube
}
}
闭包
//本质是功能更灵活的代码块,可以直接作为返回值被返回
//在闭包里不要给参数写外部参数名,因为Xcode不会提示,还要自己写,很麻烦
var square3 = {
(val:Int) -> Int in
return val*val
}
print(square3(5))
//在闭包的后面添加圆括号来调用闭包
var resultt2 = {
(base:Int,exponent:Int) -> Int in
var result = 1
for _ in 1...exponent
{
result *= base
}
return result
}(3, 4)
print(resultt2)
//省略形参类型,返回值类型的闭包
var square4:(Int) ->Int = {(val) in return val*val}
//省略了参数类型,参数列表的那个圆括号也可以省略
var square6:(Int) ->Int = {val in return val*val}
print(square6(5))
var result3:Int = {base, exponent in
var result = 1
for _ in 1...exponent
{
result *= base
}
return result
}(4, 3)//因为这个地方有声明int类型的变量,所以不用指定返回值类型
//上面两个闭包因为有声明闭包类型变量,所以也可以不声明返回值
//省略return
//如果闭包表达式的执行体只有一行代码,而且这行代码的返回值将作为闭包表达式的返回值,那么swift允许省略return关键字
var square7:(Int) ->Int = {val in val*val}
var square8 = {(val:Int) -> Int in val*val*val}
print(square7(3))
print(square8(3))
//省略形参名
var square9:(Int) ->Int = {$0 * $0}
var result4:Int = {
var result = 1
for _ in 1...$0
{
result *= $1
}
return result
}(3, 4)
//尾随闭包
//当函数的最后一个参数是一个函数类型的时候,可以用闭包来进行传参,然后把小括号放在闭包前面,把闭包给单独放置在外面
func map2(var data data:[Int], fn:(Int) -> Int) -> [Int]
{
for var i = 0, len = data.count; i<len; i++
{
data[i] = fn(data[i])
}
return data
}
var data2 = [3, 4, 5, 6, 7]
print("原数据(data2)")//"原数据[3, 4, 5, 6, 7] "
var rvt1 = map2(data: data2){$0 * $0}
var rvt3 = map2(data: data2){
var result = 1
for index in 2...$0
{
result *= index
}
return result
}
//如果调用函数时只需要闭包表达式一个参数,那么使用尾随闭包时,swift甚至允许程序省略调用函数的圆括号
//闭包可以捕获上下文中的变量和常量
//每个闭包都会持有一个它所捕获的变量的副本,所以,闭包执行与原来所在的函数并没有联系
//闭包是引用类型,所以即使是声明成常量也可以改变内部值
func makeArray(ele:String) -> () ->[String]
{
var arr:[String] = []
func addElement() ->[String]
{
arr.append(ele)
return arr
}
return addElement
}
let add1 = makeArray("sun")
print(add1())
print(add1())
let add2 = makeArray("zhu")
print(add2())
print(add2())