swift4.1 系统学习十 函数

简介: swift的函数与其他语言中的函数还是有很多的不同点的, 我们在本节中一起学习swift中的函数都有哪些特性。辅助文件, 在“统一的函数引用体系”中会用到。

swift的函数与其他语言中的函数还是有很多的不同点的, 我们在本节中一起学习swift中的函数都有哪些特性。

辅助文件, 在“统一的函数引用体系”中会用到。

//
//  test.h
//  swift10
//
//  Created by iOS on 2018/10/10.
//  Copyright © 2018年 weiman. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface test : NSObject

//g_block将是我们在是swift源文件中操作的Block对象
extern void (^ _Nullable g_block)(void);
//CTest函数用于查看回调效果。
extern void CTest(void);

@end

NS_ASSUME_NONNULL_END

//
//  test.m
//  swift10
//
//  Created by iOS on 2018/10/10.
//  Copyright © 2018年 weiman. All rights reserved.
//

#import "test.h"

@implementation test

void (^ _Nullable g_block)(void) = NULL;

void CTest(void) {
    if (g_block != NULL) {
        g_block();
    }
}

@end

本节主要内容:

// 函数
/*
学过任何一门语言的小伙伴们对函数都会感到不陌生。
Apple官方将swift中的函数定义为: 执行一个特定任务的,自包含的代码块。
*/

// 1. 函数的定义和调用
/*
func 函数名(参数1,参数2,...) -> 返回值 {
函数体
}
注意: 如果没有返回值, “->返回值” 可以省略
*/

//
//  main.swift
//  swift10
//
//  Created by iOS on 2018/9/29.
//  Copyright © 2018年 weiman. All rights reserved.
//

import Foundation

do {
    //无参数、无返回值的函数
    func hello() {
        print("你好")
    }
    
    //无参数,有返回值的函数
    func helloWorld() -> String {
        return "你好啊, 嘈杂的世界"
    }
    
    //有参数,无返回值的函数
    func hello(name: String) {
        print("你好, \(name)")
    }
    
    // 有参数,有返回值的函数
    func helloWorld(name: String) -> String {
        return "你好, \(name)"
    }
    
    //函数调用
    hello()
    hello(name: "太阳")
    let a = helloWorld()
    print(a)
    let b = helloWorld(name: "月亮")
    print(b)
}

do {
    func add(a1: [Int], a2: [Int]) -> [Int] {
        return a1 + a2
    }
    
    let a = add(a1: [1, 2, 3], a2: [4, 5, 6])
    print(a)
    
    // 求数组中的最大值和最小值
    func maxAndMin(a: [Int]) -> (max: Int, min: Int) {
        
        var max = a[0]
        var min = a[0]
        for i in a {
            if i > max { max = i }
            if i < min { min = i }
        }
        return (max, min)
    }
    
    let value = maxAndMin(a: [8,3,5,3,2,5,78,4,3,2,3,45,43,333,65,456,886,3433,33,44,56])
    print("max: \(value.max), min: \(value.min)")
}

// 2. 函数的实参标签
/*
每个函数否包含一个实参标签和一个形参名。
注意:

  1. 实参标签可以省略,但是形参名不能省略;
  2. 实参标签可以相同,形参名不能相同;
    */
do {
    func myFunc(firstName name: String, secondName name2: String) -> String {
        let str = name + "·" + name2
        return str
    }
    
    // 调用
    let name = myFunc(firstName: "迈克尔", secondName: "杰克逊")
    print(name)
}

// 3. 默认形参值
/*
swift编程语言可以对函数形参设置一个默认值。如果一个形参具有一个默认值,那么我们在调用
这个函数的时候可以无需对此参数传递实参,也就是说带有默认值的形参所对应的实参可以缺省。
*/

do {
    func hello(name: String = "wrold") {
        print("hello, \(name)")
    }
    
    //调用
    hello()
    hello(name: "🇨🇳")
    
    /*
     打印:
     hello, wrold
     hello, 🇨🇳
     */
    
    /*
     注意:
     swift的默认参数与C++相比更加的灵活,因为它不仅仅可以放在最后,
还可以放在参数列表的任何位置。
     */
    
    func myHello(name: String, years: String = "2018", ages: Int) {
        print("hello, \(name), 今年是\(years)年, 我已经编程\(ages)年了")
    }
    
    myHello(name: "杰克", ages: 10)
    myHello(name: "小土豆", years: "2020", ages: 5)
}

// 4. 不定个数的形参
/*
swift语言和C语言一样,支持不定个数的形参。
当我们使用不定个数的形参时,可以将它视作为它所指定类型的额数组,我们可以通过count属性获取实参所
传递过来的参数个数;通过下标操作符来获取对应的实参值。
*/

do {
    func foo(a: Int, b: Int...) {
        var sum = a
        if b.count > 0 {
            for i in b {
                sum += i
            }
        }
        print("sum = \(sum)")
    }
    
    foo(a: 0)
    foo(a: 0, b: 1)
    foo(a: 0, b: 1, 2, 3, 4, 5)
    
    func boo(a: Int..., b: Int = -1) {
        if a.count > 0 {
            print("value = \(a[0] + a[1])")
        } else {
            print("value = \(b)")
        }
    }
    
    boo()
    boo(a: 1, 2, 3)
    boo(a: 1, 2, 3, 4, b: 10)
    boo(b: 100)
}

// 5. 输入输出形参(inout)
/*
在swift语言中,所有的形参默认都是常量。因此我们在函数体内如果对一个普通的形参修改其值,那么
就会引发编译报错。
swift引入了一种输入输出形参,使得该形参的值不仅能被修改,而且还能影响它所对应的实参值。
//实现步骤

  1. 当函数在调用前,先将实参的值拷贝到所对应的输入输出形参中。
  2. 在执行函数中的代码时,对输入输出形参的值进行修改。
  3. 在函数返回之后,将修改后输入输出形参的值拷贝回对应的实参中。
    */
do {
    func foo(a: Int, b: inout Int) {
        b += a
    }
    
    var x = 100
    
    foo(a: 10, b: &x)
    print("x = \(x)")
    // 输出: x = 110 , 在函数内部,b = 110, 函数外部的参数x也跟着改变了,这就是 inout的作用
    
    var array = [1, 2, 3]

    foo(a: array[0], b: &array[2])
    print("array: \(array)")
    // 结果: array: [1, 2, 4]
    
    func boo(t: inout (Double, Double)) {
        t.0 *= 0.5
        t.1 *= 0.5
    }
    
    var point = (10.0, 20.0)
    boo(t: &point)
    print("point: \(point)")
}

// 6. 函数重载
/*
swift 语言跟C++ 一样,默认支持函数重载。
什么是函数重载?
如果在同一作用域以及名字空间中出现一组相同名字的函数,这些函数具有不同的形参类型或者形参个数,或是
带有不同的返回类型,那么称这组函数为重载函数。
*/

do {
    func foo() {
        print("无参数")
    }
    
    func foo(a: Int) {
        print("有一个整型参数 \(a)")
    }
    
    func foo(b: Float) {
        print("有一个浮点型参数 \(b)")
    }
    
    foo()
    foo(a: 10)
    foo(b: 20.0)
    
}

// 7. 函数类型和函数签名
/*
函数类型是由其形参列表中各个形参的类型与函数返回类型构成。
*/

do {
    // 返回值为 () -> void
    func foo() {
        print("这是一个函数")
    }
    
    // 返回值为 (Int) -> void
    func foo(_ a: Int) {
        print("有参数的函数 \(a)")
    }
    
    // 返回值为 (Int, String) -> String
    func foo(a: Int, b: String) -> String {
        return "\(a), \(b)"
    }
    
    let b = foo(_ :)
    b(100)
    
    let a = foo(a: b:)
    let r = a(10, "11")
    print(r)
    
    // 定义一个函数magic,含有一个输入输出参数 func,类型是 (Int) -> Void
    // magic的函数的类型为 (inout (Int) -> Void) -> Void
    func magic(fun: inout (Int) -> Void) {
        fun = foo(_ :)
    }
    
    var ref = foo(_ :)
    
    magic(fun: &ref)
    ref(200)
    
    let magicRef: (inout (Int) -> Void) -> Void = magic
    magicRef(&ref)
}

/*
 函数签名
 函数签名这个语法特性其实引申自OC的方法签名。在swift语言中,一个函数名并不是唯一标识当前函数的标志。
 而是需要通过结合每个形参所持有的实参标签。
 */
do {
    func foo() {
        print("foo")
    }
    
    func boo(_ : Void) {
        print("boo")
    }
    
    func moo(a: Int) {
        print("moo")
    }
    
    func poo(a: Int, _: Int, c: Int) {
        print("poo")
    }
    
    //调用
    foo()
    boo(())
    moo(a: 10)
    poo(a: 100, 20, c: 77)
    
}

do {
    func foo(_ : Void) {
        print("foo Void")
    }
    
    func foo(a: Int) {
        print("foo Int")
    }
    
    func foo(i: Float) {
        print("foo float")
    }
    
    func foo(j: Double) {
        print("foo Double")
    }
    
    func foo(_: Void, _: Int) {
        print("foo Void,Int")
    }
    
    let ref1 = foo(_:) as (()) -> Void
    ref1(())
    
    let ref2 = foo(a:)
    ref2(100)
    
    let ref3 = foo(i:)
    ref3(0.5)
    
    let ref4 = foo(_: _:)
    ref4((), 10)
}

print("\n")

//8.嵌套函数定义
/*
swift语言中,允许在函数中定义一个嵌套函数,这是很多其他语言多不具备的。
*/

do {
    func hello(a: Int) {
        print("value = \(a)")
    }
    
    func outside() -> (Int) -> Void {
        let a = 10
        var b = 20
        
        //定义一个嵌套函数
        func inner(input: Int) {
            print("inner value = \(input)")
        }
        
        func hello(input: Int) {
            b += a + input
            print("b = \(b)")
        }
        
        //调用内部函数
        inner(input: a)
        
        return hello
    }
    
    hello(a: 100)
    let ref = outside()
    ref(5)
    ref(5)
    
    /*
     输出结果:
     value = 100
     inner value = 10
     b = 35
     b = 50
     */
}

// swift的嵌套函数不仅可以直接定义在函数体内,还可以定义在语句块作用域内。
do {
    func foo() {
        print("外面的foo")
        
        func foo() {
            print("中层的foo")
            
            func foo() {
                print("内部的foo")
            }
            
            //调用
            foo()
        }
        foo()
    }
    
    foo()
}

/*
 打印结果:
 外面的foo
 中层的foo
 内部的foo
 
 个人建议:在没有必要的情况下,还是不要这么写,可能自己都给绕晕了。
 */

//9.统一的函数引用体系
/*
什么是统一的函数引用?
就是在swift中,我们可以定义一个引用对象,这个对象除了能够引用函数之外,还能引用闭包以及结构体、
枚举、类类型对象的实例方法。
*/

print("\n ------------统一的函数引用体系----------------- ")
do {
    func foo () {
        print("foo")
    }
    
    var ref = foo
    ref()
    // g_block是OC中定义的Block对象,现在指向foo函数
    g_block = foo
    // 调用OC中的CTest,判断g_block是否为空
    CTest()
    /*
     打印结果
     foo
     foo
     */
    // 说明g_block已经指向了foo函数
    
    // 定义一个boo函数,返回值是() -> Void
    func boo() -> () -> Void {
        var a = 10
        /*
         定义一个嵌套的函数inner,捕获了局部变量a,因此它是一个闭包
         */
        func inner() {
            a += 10
            print("a = \(a)")
        }
        
        return inner
    }
    
    ref = boo()
    ref()
    
    
    g_block = boo()
    CTest()
    /*
     打印结果:
     a = 20
     a = 20
     */
    
    //从打印结果看,g_block还是不为空,并且指向了inner函数
    
    // 定义了一个结构体类型
    struct MyStruct {
        
        let a: Int, b: Double
        
        func method () {
            print("a = \(a), b = \(b)")
        }
    }
    
    let obj = MyStruct.init(a: 10, b: 100.0)
    
    //ref指向了一个结构体的实例方法
    ref = obj.method
    ref()
    
    g_block = ref
    CTest()
    
    /*
     结果:
     a = 10, b = 100.0
     a = 10, b = 100.0
     */
    
    /*
     小结:
     我们发现,swift中的一个函数类型引用可以指向函数、闭包、实例方法三种类型中的任意一种,这是很方便也是很先进的。
     我们跟其他语言做个对比:
     C++:指向函数的指针类型与指向成员函数的指针类型是完全不一样的。
     OC:没有指向成员函数的指针,而是统一使用selector机制。
     Java:使用指向方法的引用更加的繁琐。
     
     比较遗憾的是,函数引用不能比较相等性,因为swift会对函数、闭包做相关优化,因此在运行时无法确定两个引用是否是完全相同的。
     */
}

// 把函数的引用放在数组、字典等容器中。
do {
    func foo () {
        print("这是一个函数")
    }
    
    let ref = foo
    
    let array = [foo, ref]
    
    // 调用第一个元素
    array[0]()
    // 调用第二个元素
    array[1]()
    
//    报错:Binary operator '==' cannot be applied to two '() -> ()' operands
//    let isequal = foo == ref
//    print("isequal = \(isequal)")
}


目录
相关文章
|
4月前
|
Swift iOS开发 Kotlin
苹果iOS新手开发之Swift中实现类似Kotlin的作用域函数
Swift可通过扩展实现类似Kotlin作用域函数效果。如自定义`let`, `run`, `with`, `apply`, `also`,增强代码可读性和简洁性。虽无直接内置支持,但利用Swift特性可达成相似功能。
59 7
|
5月前
|
Swift C++ 索引
Swift开发——简单函数实例
函数是编程的基础,用于封装特定功能的代码。它们有关键词func、函数名、参数列表(可为空)和返回类型。多返回值可通过元组、数组、inout参数或可选类型实现。例如,返回元组 `(value1, value2)`,数组 `[value1, value2]` 或使用可选数组 `[[Double]]?`。函数可以作为其他函数的参数,类似闭包或Lambda表达式。在Swift中,示例展示了通过元组、带索引的元组、数组和可选类型返回多个值的函数。还演示了如何使用inout参数交换变量值。
94 5
Swift开发——简单函数实例
|
6月前
|
人工智能 物联网 API
LLM 大模型学习必知必会系列(十三):基于SWIFT的VLLM推理加速与部署实战
LLM 大模型学习必知必会系列(十三):基于SWIFT的VLLM推理加速与部署实战
LLM 大模型学习必知必会系列(十三):基于SWIFT的VLLM推理加速与部署实战
|
6月前
Swift4.0判断本函数是否在其它类有相同的方法
Swift4.0判断本函数是否在其它类有相同的方法
42 0
|
6月前
|
存储 API Swift
【Swift开发专栏】Swift函数与闭包的实战应用
【4月更文挑战第30天】本文介绍了 Swift 中函数和闭包的实战应用。首先,函数的基本使用包括定义、参数与返回值、函数类型以及高级技巧如嵌套函数。接着,讨论了闭包的语法,包括无名函数、作为函数参数、简写形式和尾随闭包。最后,展示了函数和闭包在实战中的应用,如排序过滤集合和处理异步任务的回调。
45 0
|
6月前
|
存储 Swift
Swift 语言:什么是闭包(Closure)?它们与函数的区别是什么?
Swift 语言:什么是闭包(Closure)?它们与函数的区别是什么?
115 1
|
6月前
|
Swift
Swift中的函数
Swift中的函数
42 1
|
6月前
|
存储 Swift
Swift中,函数和闭包
Swift中,函数和闭包
63 1
|
Swift iOS开发
23 Swift中如何定义和使用函数
Swift中如何定义和使用函数
87 0
|
Swift
Swift Debug 和 Release 中 print() 函数调试切换
Swift Debug 和 Release 中 print() 函数调试切换
70 0