前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Swift3.0 - 函数和闭包

Swift3.0 - 函数和闭包

作者头像
酷走天涯
发布于 2018-09-14 06:47:33
发布于 2018-09-14 06:47:33
1.1K00
代码可运行
举报
运行总次数:0
代码可运行
函数的几种类型
  • 无参无返
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func greet() -> Void {
}
// 或者
func greet(){    
}
  • 有参无返
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func greet(person: String, day: String) {
    return "Hello \\\\(person), today is \\\\(day)."
}
greet(person: "Bob", day: "Tuesday")

思考1: 如何省略外部参数名?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  greet("John", "Wednesday")
 // 实现代码
  func greet(_ person: String, _ day: String) -> String {
    return "Hello \\\\(person), today is \\\\(day)."
}
  • 有参有返
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func greet(_ person: String, on day: String) {
    return "Hello \\\\(person), today is \\\\(day)."
}
  • 无参有返
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  func greet(_ person: String, on day: String) -> String {
    return "Hello \\\\(person), today is \\\\(day)."
}

中级思考
  • 参数和返回值

1.参数可以是那些?

基本类型的值,对象,数组,字典,元组,可变数量的参数,函数,闭包函数,协议,结构体,枚举值

2.怎么定义参数

a. 单值

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 func calculate(a:Int){
    let b = a
}

b.多值

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func calculate(a:Int...){
    for _ in a{
     }
}
// 调用
calculate(a: 1,2,3,4,5,6)

c.元组

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func calculate(a:(name:String,age:Int)){
    let name = a.name;
    let age = a.age;
}

d.数组

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 func calculate(a:[String]){
    for student in a {
}
}

e.定义字典

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 func calculate(a:[String:Int]){
    for student in a {
        print(student.key)
        print(student.value)
  }
}

f.函数作为参数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 func add(a:Int,b:Int)->Int{// 作为函数参数的函数
  return a+b
}

func calculate(a:(Int,Int)->Int){// 定义的参数为函数的函数
    a(2,1)// 执行函数
}
calculate(a: add);// 执行函数

g.上面函数的闭包写法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  calculate { (a,b) -> Int in
    return a+b
}
calculate { (a,b) in a+b } // 省略写法(由于swift有推断能力,这样写它就能帮你推断出来上面的写法)

h. 参数为协议的方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 protocol Player{  // 定义协议
      func play()
}

func playMusicWithPlayer(player:Player){
    player.play()
}

i.参数为结构体

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct Student{
    var name:String
    var age:Int
};

func getStudentDescription(student:Student){
    print(student.name)
    print(student.age)
}

j.参数为枚举类型

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 定义枚举值
enum CarType:String{
  case Lincoln = "林肯"
  case MERCURY = "水星"
  case SUZUKI = "铃木"
}
// 参数为协议的方法
func describeCar(carType:CarType){
    print(carType.rawValue);
}
  • 函数的内部定义函数

需求: 创建一个接口,输入true 返回 两个数相加的函数,输入false 返回两个数相减的函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func generateFuncByFlag(flag:Bool)->(Int,Int)->Int{
// 定义两数字相加函数
func add(a:Int,b:Int)->Int{
    return a+b;
}
// 定义两数字相减函数
func decrease(a:Int,b:Int)->Int{
    return a-b;
}
// 根据输入的条件返回对应的函数
if flag{
    return add
}else{
    return decrease
}
}
// 生成对应的函数
let addFunc = generateFuncByFlag(flag: false)
// 执行返回的函数
print(addFunc(1,2))
  • 设置默认参数值
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func addStudent(student:(name:String,score:Double)=("姓名",12)){
    print(student.name)
    print(student.1)
}
addStudent()
addStudent(student: ("酷走天涯",99))

提示:

元组类型,不能分别给参数赋值,比如像下面这样

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 这样是错误的方式
func addStudent(student:(name:String = "酷走天涯",score:Double = 12 )){
print(student.name)
print(student.1)
}
  • inout的使用

需求: 创建一个函数,交换两个Int类型值

a.如果参数为let修饰的常量

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func swapTwoInts( a:  Int, b: Int){
let temporaryA = a
a = b
b = temporaryA
}

提示:

报错:系统提示错误,说常量不能修改值

b.我们将参数变成变量var

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func swapTwoInts( var a:  Int, var b: Int){
let temporaryA = a
a = b
b = temporaryA
}

提示:

报错,不能使用var 修饰参数

c.inout 修饰的参数可以修改值

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func swapTwoInts(  a: inout Int, b:inout Int){
    let temporaryA = a
    a = b
    b = temporaryA
}
var a = 30
var b = 40
swapTwoInts(a: &a, b: &b)
print(a)
print(b)

运行结果:

40 30

你需要注意的

1.inout的位置 在: 后面,数据类型前面 2.inout 修饰的参数不能有默认值 3.inout 不能用于修饰多值(如a:Int...)

  • 定义函数类型的变量
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  func swapTwoInts(  a: inout Int , b:inout Int){
    let temporaryA = a
    a = b
    b = temporaryA
  }

  var swap1:( inout Int, inout Int)->Void = swapTwoInts

注意:函数类型的变量不能用标签修饰参数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 错误的写法  不能使用a,b标签
var swap1:( a :inout Int, b: inout Int)->Void = swapTwoInts
// 你应该像下面这样
var swap1:( _ :inout Int, _: inout Int)->Void = swapTwoInts
// 或者下面这样也可以,a,b 不一定要和实际函数对应
var swap1:( _ a:inout Int, _ b: inout Int)->Void = swapTwoInts
// 建议还是用下面这种
var swap1:( inout Int, inout Int)->Void = swapTwoInts
  • 定义闭包类型数据
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
let customerProvider = { customersInLine.remove(at: 0)}
print(customersInLine.count)
print("Now serving \\\\(customerProvider())!")
print(customersInLine.count)

运行结果:

5 Now serving Chris! 4 提示:上面那种闭包其实是五参有返的闭包形式,原形如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let customerProvider:()->String= { customersInLine.remove(at: 0)}
  • 关键字 @discardableResult

先看一段代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class OSStudent{
var name:String!
var score:Double!
func setNewScore(score:Double)->Bool{
    if name == nil || name.isEmpty{
    return false
    }
    self.score = score
    return true
}
}
OSStudent().setNewScore(score: 34.0)

注意:

函数的setNewScore 方法有返回值,但是调用的时候,没有使用常量或者变量接受这个返回值,系统会产生警告如下图

让学习成为一种习惯

我们通过加关键字@discardableResult去除那种警告

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@discardableResult
func setNewScore(score:Double)->Bool{
    if name == nil || name.isEmpty{
    return false
    }
    self.score = score
    return true
}

注意

如果你没有添加这个关键字,系统默认添加的是 @warn_unused_result ,有返回值没有使用会发生警告


高级思考
  • 如何获取,函数自己的名称,在那个文件中,在文件多少行
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 定义一个获取获取函数名称,获取文件路径的函数
func getFunctionName(name:String = #function,line:Int =   #line,file:String = #file){
print(name)
print(line)
print(file)
}
// 比如我们要获取下面函数的信息,只需要将函数写入要获取信息函数的内部调用即可
func  getUserName(){
 getFunctionName()
 }
 // 执行函数
getUserName()

运行结果:

getUserName() 152 /var/folders/gk/zc__29js08g1g03xrzgl8m1m0000gn/T/./lldb/2184/playground65.swift

  • 编译器可能没有那么智能
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 定义一个父类
class Person{
}
// 定义一个男人
class Man:Person{
}
// 定义一个女人
class Woman:Person{
}

// 定义三个描述人的方法
func describePerson(_ person:Person){
    print("我是人类")
}

func describePerson(_ woman:Woman){
    print("我是女人")
}

func describePerson(_ person:Man){
    print("我是男人")
}

 // 定义一个描述男人的女人的方法
func descripePerson(_ person:Person,_ woman:Woman){
  describePerson(person)
  describePerson(woman)
}
// 执行
descripePerson(Man(), Woman())

结果:

我是人类 我是女人

分析:

参数man 在值没有传入之前,被默认为Person 进行编译了,所以不管我们传入男人或者女人都之调用人类描述的方法。

那么我们应该怎么处理这个问题呢?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func descripePerson(_ person:Person,_ woman:Woman){
if person is Woman{
    describePerson(person as! Woman)
}else{
    describePerson(person as! Man)
}
describePerson(woman)
}

运行结果:

我是男人 我是女人

下面这种写法也是可以的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func descripePerson(_ person:Person,_ woman:Woman){
if let woman = person as?  Woman{
    describePerson(woman)
}else{
    describePerson(person as! Man)
}
describePerson(woman)
}
  • 泛型

需求: 设计一个接口,交换两个元素(数字,字符,对象)的值

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  func swap<T>(a:inout T,b:inout T){
    (a,b) = (b,a)
 }

测试1

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var a = "你好"
var b = "酷走天涯"
print("交换前---------------------")
print(a)
print(b)
swap(&a, &b)
print("交换后----------------------")
print(a)
print(b)

运行结果:

交换前--------------------- 你好 酷走天涯 交换后---------------------- 酷走天涯 你好

测试2

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Woman{
    var name = "女人"
    init(name:String) {
        self.name = name
    }
}
print("交换前---------------------")
print(a.name)
print(b.name)
swap(&a, &b)
print("交换后----------------------")
print(a.name)
print(b.name)

运行:

交换前--------------------- 小红 小白 交换后---------------------- 小白 小红

提示

交换的必须是相同的对象

*@escaping 用法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var downloadComplate:(Bool)->()
func downloadResource(url:String,complate:(Bool)->()){
  downloadComplate = complate
  // 异步下载,下载完成调动
  downloadComplate(true)
  // 下载失败
  downloadComplate(false)
}

运行

编译报错,提示没有加@escaping

@escaping 作用

我们经常在下载等异步操作完成时,才调用闭包函数,我们有可能暂时不要把这个闭包存放在数组中,或者使用属性去引用它,那么这个时候就需要使用这个关键了

修改代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var downloadComplate:((Bool)->())
func downloadResource(url:String,complate:@escaping (Bool)->())  {
  downloadComplate = complate
 // 异步下载,下载完成调动
  downloadComplate(true)
  // 下载失败
  downloadComplate(false)
}

报错提示:

downloadComplate 使用之前必须初始化

所以进行初始化

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var downloadComplate:((Bool)->())! // 加? 也可以,但是在调用时,要进行解包
  func downloadResource(url:String,complate:@escaping (Bool)->())  {
  downloadComplate = complate
 // 异步下载,下载完成调动
  downloadComplate(true)
  // 下载失败
  downloadComplate(false)
}

我们如何调用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
downloadResource(url: "www.baidu.com") { (flag) in
print(flag)
}

如果我们不需要引用完全可以不使用关键字@escaping

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func someFunctionWithNonescapingClosure(closure: () -> Void) {
    closure()
}
  • 关键字@autoclosure 的用法

a.不加自动闭包的关键字@autoclosure

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func serve(customer customerProvider: () -> String) {
    print(customerProvider())
}
serve { () -> String in
    return "没加@autoclosure"
}

运行结果:

没加@autoclosure

b.添加@autoclouse

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func serve(customer customerProvider: @autoclosure () -> String)     {
    print (customerProvider())
}
serve(customer: "加了@autoclosure") // 调用

是不是感觉参数像是字符串,而是下面这样,系统帮你自动闭包了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
serve(customer: { "加了@autoclosure"})

如果还不清楚,其实是参数是一个返回值

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
serve(customer: { return "加了@autoclosure"})

完整的写法其实是下面这样

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
serve(customer: { () in return "加了@autoclosure"})

c. @autoclosure 和 @escaping 组合使用方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func serve(customer customerProvider: @autoclosure @escaping() -> String) {
customerProvider1 = customerProvider
print (customerProvider())
}
serve(customer:  customersInLine.remove(at: 0))

提示:

其实自动闭包给人可能造成一种表意不清的感觉,建议使用的时候,一定要注释说明,或者不要使用。

d. @noescape

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func calculate(fun :@noescape ()->()){
}

提示:

1.系统默认为@onescape 的类型 2.不能被引用 3.不能在异步执行

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016.10.04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
1 条评论
热度
最新
brew里面根本没有这个包
brew里面根本没有这个包
回复回复点赞举报
推荐阅读
使用kubeadm工具箱创建kubernetes1.9集群
版权声明:本文为木偶人shaon原创文章,转载请注明原文地址,非常感谢。 https://blog.csdn.net/wh211212/article/details/79209551
shaonbean
2019/05/26
5610
K8S(V1.10.1)高可用集群超详细版本(包含Dashboard、Rancher)
六台主机配置、停防火墙、关闭Swap、关闭Selinux、设置内核、安装依赖包、配置ntp(配置完后建议重启一次)
全栈程序员站长
2022/06/29
3330
K8S(V1.10.1)高可用集群超详细版本(包含Dashboard、Rancher)
Centos7安装K8S集群环境
kubelet不支持SELinux, 这里需要将SELinux设置为permissive模式
用户1392128
2024/01/08
1.6K0
部署k8s集群(k8s集群搭建详细实践版)
Kubeadm是一个K8s部署工具,提供kubeadm init和kubeadm join,用于快速部署Kubernetes集群。
zjiekou
2022/11/12
21.8K5
国内 CentOS 7 安装 K8S v1.29.2(CRI:containerd),通过安装 K8S,了解 K8S 的核心概念
通过安装 K8S,了解 K8S 的核心概念:控制面、CRI、CNI、Deployment、Service、sandbox 等,本文不仅包含安装流程,而且包含丰富的 Troubeshooting 实战,以及解释这背后发生了什么。
SRE扫地僧
2024/04/27
3.4K0
国内 CentOS 7 安装 K8S v1.29.2(CRI:containerd),通过安装 K8S,了解 K8S 的核心概念
kubernetes-1:使用kubeadm搭建K8S单master节点集群
现在官方推荐的是kubespray,但也是基于kubeadm;除此之外,还有kind,minikube,但是并不试用于部署生产级别集群。
千里行走
2019/07/03
2.1K0
k8s学习一:使用kubeadm安装k8s
在学习整个k8s之前,先想办法搭建个k8s出现成果,然后根据这个成果进行深入学习,才会让人有学习的动力,本文将记录自己的安装k8s教程
仙士可
2022/09/13
6760
k8s学习一:使用kubeadm安装k8s
CentOS7.7部署k8s(1 master + 2 node)
VMware创建三个vm,规格2cpu 4G mem 200G disk,一个NAT网卡
后端云
2020/04/22
1.4K0
CentOS7.7部署k8s(1 master + 2 node)
K8s 安装
如果你的节点上面有科学上网的工具,可以忽略这一步,我们需要提前将所需的gcr.io上面的镜像下载到节点上面,当然前提条件是你已经成功安装了docker。
分母为零
2019/07/04
1.8K0
K8s 安装
利用GPU服务器实现边云协同推理
持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情
鳄鱼儿
2024/05/22
2530
利用GPU服务器实现边云协同推理
附003.Kubeadm部署Kubernetes
Kubeadm 是一个工具,它提供了 kubeadm init 以及 kubeadm join 这两个命令作为快速创建 kubernetes 集群的最佳实践。
木二
2019/07/01
8400
手动搭建K8S环境
在三台机器上均安装docker、kubeadm、kubelet,在master节点安装kubectl
谢公子
2022/11/29
1K0
手动搭建K8S环境
公网环境搭建 k8s 集群
笔者利用手头几台云服务器搭建 k8s 集群,由于这几台云服务属于不同的云服务厂商,无法搭建局域网环境的 k8s 集群,故笔者搭建的是公网环境的 k8s 集群,在此做个记录, 以下均在 ubuntu 20.04 环境下进行
菜菜cc
2022/11/15
3.4K0
公网环境搭建 k8s 集群
kubernetes炼气期之k8s平台快速搭建
环境说明 功能名称 IP 配置 k8s-master 192.168.10.231 4c8g k8s-node1 192.168.10.232 8c16g K8s-node2 192.168.10.233 8c16g k8s-node3 192.168.10.234 8c16g k8s-node4 192.168.10.235 8c16g 环境初始化 更新环境 yum update -y yum install -y wget vim net-tools epel-release 关闭filewal
公众号: 云原生生态圈
2020/06/15
5220
kubeadm安装Kubernetes1.11集群
9、设置内核(可不设置) echo "* soft nofile 65536" >> /etc/security/limits.conf echo "* hard nofile 65536" >> /etc/security/limits.conf echo "* soft nproc 65536" >> /etc/security/limits.conf echo "* hard nproc 65536" >> /etc/security/limits.conf echo "* soft memlock unlimited" >> /etc/security/limits.conf echo "* hard memlock unlimited" >> /etc/security/limits.conf
菲宇
2019/06/12
1.8K0
kubeadm安装Kubernetes1.11集群
CentOS7系统上Kubernetes集群搭建
在自己的Mac系统里面利用Parallels Desktop创建3台虚拟机,具体信息如下:
chengcheng222e
2021/11/04
1.7K0
Kubernetes 使用kubeadm创建集群
注意,安装docker时,需要指Kubenetes支持的版本(参见如下),如果安装的docker版本过高导致,会提示以下问题
授客
2021/09/26
3.4K0
kubeadm实现K8S的HA
(1)k8s各节点SSH设置免密登录 所有节点用root用户操作,全部设置免密登陆,不做细分。
用户1499526
2019/07/15
1.2K0
CentOS7.7部署k8s(3 master + 3 node + 1 client)
VMware创建7个vm,规格2cpu 2G mem 200G disk,一个NAT网卡
后端云
2020/04/22
2.3K0
CentOS7.7部署k8s(3 master + 3 node + 1 client)
K8S学习笔记之二进制的方式创建一个Kubernetes集群
Minikube是一个工具,可以在本地快速运行一个单点的Kubernetes,尝试Kubernetes或日常开发的用户使用。不能用于生产环境。
Jetpropelledsnake21
2019/03/20
1.3K0
K8S学习笔记之二进制的方式创建一个Kubernetes集群
推荐阅读
相关推荐
使用kubeadm工具箱创建kubernetes1.9集群
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文