本文共 8913 字,大约阅读时间需要 29 分钟。
swift的函数与其他语言中的函数还是有很多的不同点的, 我们在本节中一起学习swift中的函数都有哪些特性。
辅助文件, 在“统一的函数引用体系”中会用到。
//// test.h// swift10//// Created by iOS on 2018/10/10.// Copyright © 2018年 weiman. All rights reserved.//#importNS_ASSUME_NONNULL_BEGIN@interface test : NSObject//g_block将是我们在是swift源文件中操作的Block对象extern void (^ _Nullable g_block)(void);//CTest函数用于查看回调效果。extern void CTest(void);@endNS_ASSUME_NONNULL_END
//// test.m// swift10//// Created by iOS on 2018/10/10.// Copyright © 2018年 weiman. All rights reserved.//#import "test.h"@implementation testvoid (^ _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 Foundationdo { //无参数、无返回值的函数 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. 函数的实参标签
/* 每个函数否包含一个实参标签和一个形参名。 注意: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引入了一种输入输出形参,使得该形参的值不仅能被修改,而且还能影响它所对应的实参值。 //实现步骤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)")}
转载地址:http://mbqyx.baihongyu.com/