从 函数 到 Swift

2019-10-30  本文已影响0人  overla5

函数是一段完成某个事务的代码片段

定义

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("我是空的")
}

可选绑定 if let 介绍

函数的标签以及参数

每个函数都包含 参数标签参数名称,而 参数标签大大增加了代码的可读性

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))

后续还会在补充 还请多多指点

谢谢

上一篇下一篇

猜你喜欢

热点阅读