函数是一段完成某个事务的代码片段
定义
func 函数名(参数列表) -> 返回值类型 {
// :TODO
return or not
}
* 函数的参数可以省略,但是包裹着参数的 () 不可以省略
* 返回值为 -> void 的时候,意味着无返回值,-> void 也可以省略
* 本质来说,函数和方法是同一种东西,只不过方法是定义在函数内部的函数,我们称之为方法
类型
从参数的有无
和 返回值的有无
可以组成4种基本情况
1.无参无返
比如:我们想写一个函数 打印字符串 "helloworld"
* Void v是大写
func printAction() -> Void {
print("helloworld")
}
上面这段代码无返回值,没有return操作,可以省略 -> Void,等价于
func printAction() {
print("helloworld")
}
printAction()
/// helloworld
2.无参有返
// 没有参数,返回值的类型 是 字符串String
func printAction() -> String {
return "Swift"
}
var str = printAction() // 接收返回值
print("\(str) 是最好的语言")
/// Swift 是最好的语言
3.有参有返
// 传入 2个 Int 类型的参数,返回值也是 Int 类型
func printAction(num1: Int,num2: Int) -> Int {
return num1 + num2
}
printAction(num1: 2, num2: 3)
/// 5
4.有参无返
// 传入一个 String 类型的参数,没有返回值
func printAction(s1: String) {
print(s1)
}
printAction(s1: "Swift is ok")
/// Swift is ok
5.隐式返回
# 🐷:当函数 执行语句中的表达式 是 单一表达式的时候,我们可以省略return 字段
func printAction(num1: Int,num2: Int) -> Int {
return num1 + num2
}
上面函数等价于
func printAction(num1: Int,num2: Int) -> Int {
num1 + num2
}
6.多重返回
现在我们想做这样一件事,定义一个函数,传入一个数组,返回2个值,一个最大,一个最小
func printAction(array: [Int]) -> (min: Int, max: Int) {
// 取出数组第一个,同时赋值给 当前最小值,最大值
var curMin = array[0]
var curMax = array[0]
// 从第二个开始遍历,也就是下标1
for item in array[1..<array.count] {
if item < curMin {
curMin = item
} else if item > curMax {
curMax = item
}
}
return (curMin, curMax)
}
print(printAction(array: [1,2,3,4,5]))
/// (min: 1, max: 5)
7.可选返回类型
如果说上面的案例我们传入的数组是空呢?那么在 访问array[0]
的时候就会发生 运行时错误
所以我们需要 定义 返回值为可选型
,假如传入的数组为空时,我们返回nil
func printAction(array: [Int]) -> (min: Int, max: Int)? {
// 这里我们首先判断是否为空,为空返回nil
if array.isEmpty {
return nil
}
var curMin = array[0]
var curMax = array[0]
for item in array[1..<array.count] {
if item < curMin {
curMin = item
} else if item > curMax {
curMax = item
}
}
return (curMin, curMax)
}
# 既然返回值是可选型,那么我们取值的时候就要注意了
* 返回值类型是 元祖,我们可以定义一个元祖去接收
* 如果元祖有值,我们可以进if,反之进else
var tuples = printAction(array: [])
if let result = tuples {
print(result.0,result.1)
} else {
print("我是空的")
}
函数的标签以及参数
每个函数都包含 参数标签
和 参数名称
,而 参数标签大大增加了代码的可读性
func someFuction(参数标签 参数名称: 参数类型) {
// do something
...
// 参数标签 和 参数名称 以 空格分隔
// 参数标签可以省略
}
比如说
func eatFuction(food: String, who:String) {
print("今天和\(who) 吃了\(food)")
}
eatFuction(food: "麻辣烫", who: "表弟")
// 这样的调用 如果不明白函数内部实现的人,其实是懵逼的
// foot 和 who 有什么联系?
// 麻辣烫是表弟做的吗?
* 如果加上参数标签呢?
func eatFuction(eat food: String, with who:String) {
print("今天和\(who) 吃了\(food)")
}
那么的调用就是这样
eatFuction(eat: "kfc", with: "表弟")
// 今天和表弟一起吃了kfc
// 有没有一种豁然开朗的感觉,没错 是我带他吃的
省略参数标签 _
如果我们想省略一些参数,我们并不想知道 参数代表的含义,可以使用下划线 _
来操作
并不关心这个参数
比如:
func eatFuction(_ food: String, _ who:String) {
print("今天和\(who) 吃了\(food)")
}
eatFuction("饭", "别人")
// 今天和别人吃了饭,我管你是谁
默认参数
函数的参数中我们是可以添加默认值的,用来表达一些默认的值,也许不会修改
比如 去图书馆看书
# 含有默认值的参数列表,函数默认会提供2个初始化构造方法
# 一个包含默认值可以改,一个不包含默认值
func defuleFuction(whichPlace: String, todo: String = "读书") {
print("我每天都去\(whichPlace) \(todo)")
}
defuleFuction(whichPlace: "图书馆")
// 我每天都是图书馆看书
// 我只要写地点,不需要写干什么
* 假如我想更改这个默认值,
defuleFuction(whichPlace: "图书馆",todo: "看妹子")
// 那么我也可以去图书馆 看妹子呀
可变参数
可变参数 顾名思义就是 参数是可变的,当我们不确定参数值的数量
时,可以用 省略号...
来表示这个参数是可变的
// 我们定义一个函数,累加我们传入的数值
func variableFuction(_ varialbeStrings: Int...,num: Int) -> Int {
var total = 0
for item in varialbeStrings {
total += item
}
return total + num
}
print(variableFuction(1,2, num: 3))
// 可以看到 我把可变参数写在了第一个参数,这样是不建议的
# 注意
* 一个函数最多只能拥有一个可变参数
* 有可变参数的时候 ,最好写在后面,易读
* 有可变参数的时候,另外的参数不可以省略名称
也就是说我这么写 是错误的 ❌
func variableFuction(_ varialbeStrings: Int...,_: Int) -> Int {
// 省略了num 报错
输入输出参数 inout
这2段代码我们来看一下
// 传入一个Int 分别加 1,然后返回
✅
func addFuction(num: Int) -> Int {
return num + 1
}
❌
func addOtherFuction(num: Int) -> Int {
num += 1
return num
}
# 🐷
# 事实上Swift 会默认认为 所有可能的地方 都是 不可变的,毕竟是静态语言
# 所以 函数的声明中,参数默认都是 let 修饰的
第一种方法里,num +1 ,相当于我们创建了一个临时变量
var temp = num + 1,我们改变的是temp 的值
而第二种方法,我们是在改变num 自身的值,这是不被允许的
那么我们显示调用var ?
func addOtherFuction(var num: Int) -> Int {
num += 1
return num
}
# error: 'var' as a parameter attribute is not allowed,也是不可以的
# 所以我们引入了 inout,输入输出函数
默认情况下,函数的参数传递是值传递,因为Int 是值类型
如果想改变函数外面的变量,则需要传递变量的地址
也就是 说 inout 的本质 是 引用传递
,将变量 的指针 通过& 符号
捕获,并且修改指针指向的内存 里的值
func addOtherFuction( num: inout Int) -> Int {
num += 1
return num
}
var num1 = 9
var num2 = addOtherFuction(num: &num1)
print(num1)
print(num2)
// num1 num2 都是10
# 必须要用 & 符号,类似c语言的取值符,但实际应该更为复杂
函数类型
每个函数 都有自己的函数类型,它的函数类型 是由 参数类型
和 返回值类型
共同决定的
我们可以视这个类型为一个整体
比如
func printAction(num1: Int,num2: Int) -> Int {
return num1 + num2
}
它的函数类型就是 (Int, Int) -> Int
函数类型作为参数
这里定义了一个addFuction,传入2个数,相加并返回
func addFuction(a: Int, b: Int) -> Int {
return a + b
}
// 函数类型是 (Int, Int) -> Int
// 我们把 上面的函数作为参数 给到新的 函数
func newAddFuction(_ addName: (Int, Int) -> Int, a: Int, b: Int) {
print(addName(a,b))
}
可以看到 addFuction这个参数 就是 (Int, Int) -> Int 类型的
那么我们调用的时候 ,是不是就可以把 第一个函数 addFuction 传给 newAddFuction
newAddFuction(addFuction, a: 2, b: 3)
# 我们也可以定义一个类型 指向这个类型
# 比如 var mathFunction: (Int, Int) -> Int = addFuction
那么 newAddFuction 也可以写为:
func newAddFuction(_ addName: (Int, Int) -> Int, a: Int, b: Int) {
print(addName(a,b))
}
newAddFuction(tempFunction, a: 2, b: 3)
函数类型作返回值
把参数类型 在函数体内 当做一个整体 返回
func addFuction(a: Int, b: Int) -> Int {
return a + b
}
// 通过getAddFuction 拿到 addFuction
// 因为返回值类型 和 addFuction 类型一样 都是 (Int, Int) -> Int
func getAddFuction() -> (Int, Int) -> Int {
return addFuction
}
let newAction = getAddFuction()
print(newAction(3,4))
后续还会在补充 还请多多指点
谢谢
网友评论