Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Swift进阶六——函数和闭包

Swift进阶六——函数和闭包

作者头像
拉维
发布于 2021-01-21 11:20:44
发布于 2021-01-21 11:20:44
1.2K00
代码可运行
举报
文章被收录于专栏:iOS小生活iOS小生活
运行总次数:0
代码可运行

函数

形参和实参

形式参数,指的是是在函数的定义中,系统并没有为其分配内存空间、但是在函数里面可以使用的参数。比如下面的a就是形式参数:

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

实际参数,指的是在函数调用的时候,传递给函数的变量。这个变量是系统实实在在分配了内存空间的变量。比如下面的b就是实际参数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let b = 11play(a: b)

之前我在Swift基础语法(二)中介绍过函数的实参标签和形参名的区别,但是表述有误,在该文中,我当时由于没有理解清楚概念,而将【实际参数标签】误称为【形式参数标签】,在此勘误

每一个函数的形式参数都分为实际参数标签和形式参数名两部分:实际参数标签用在调用函数的时候,形式参数名用在函数的实现当中。默认情况下,形式参数会使用他们的形式参数名作为实际参数标签。

内嵌函数

可以在一个函数的内部定义另外一个函数,这就是内嵌函数

默认情况下,内嵌函数在外部是会被隐藏起来的,但是仍然可以通过包裹他们的函数来调用他们。包裹的函数也可以返回它内部的一个内嵌函数来在另外的范围里使用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func chooseStepFunc(back: Bool) -> (Int)->Int {    func stepForward(input: Int) -> Int { return input + 1 }    func stepBackward(input: Int) -> Int { return input - 1 }    return back ? stepBackward : stepForward}

闭包

捕获值

一个闭包能够从上下文捕获已被定义的常量和变量。即便定义的这些常量和变量的原作用域已经不存在了,闭包仍然能够在其函数体内引用和修改这些值。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func makeIncrementer(forIncrement ammount: Int) -> () -> Int {    var runningTotal = 0    func incrementer() -> Int {        runningTotal += ammount        return runningTotal    }    return incrementer}

上面的makeIncrementer函数作用是其创建一个递增器,里面的incrementer是一个内嵌函数。

内嵌函数是一个有名字且能从上层函数捕获值的闭包,因此可以从外层捕获runningTotal的值。

当内嵌函数incrementer被返回之后,外层包裹该内嵌函数的作用域(makeIncrementer)就已经不复存在了,理论上来讲runningTotal也就应该不存在了。但是由于内嵌函数incrementer是闭包,并且incrementer捕获了runningTotal的值,因此即便是定义runningTotal的外层作用域不存在了,incrementer仍然可以得到并修改runningTotal的值。

Swift中,作为一种优化,如果一个值在闭包中使用到但是并没有改变,或者一个值是在闭包的外面使用,那么Swift有可能会使用这个值的拷贝,而不是捕获。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let incrementByTen = makeIncrementer(forIncrement: 10)print(incrementByTen()) // 10print(incrementByTen()) // 20print(incrementByTen()) // 30
// 如果你创建了第二个Incrementer,他将会有一个新的、独立的runningTotal的引用。let incrementBySeven = makeIncrementer(forIncrement: 7)print(incrementBySeven()) // 7print(incrementBySeven()) // 14
print(incrementByTen()) // 40

这段代码中,一开始的incrementByTen闭包中会捕获并引用一个runningTotal。后面又新创建了一个incrementBySeven闭包,该闭包会捕获并引用一个新的runningTotal变量

在Swift中,函数和闭包都是引用类型,当你赋值一个闭包给函数的常量或者变量的时候,你实际上都是将常量和变量设置为对函数和闭包的引用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let incrementByTen = makeIncrementer(forIncrement: 10)print(incrementByTen()) // 10print(incrementByTen()) // 20print(incrementByTen()) // 30
let incrementBySeven = makeIncrementer(forIncrement: 7)print(incrementBySeven()) // 7print(incrementBySeven()) // 14
print(incrementByTen()) // 40        // 闭包是引用类型let alsoIncrementByTen = incrementByTenprint(alsoIncrementByTen()) // 50

由于闭包是引用类型,因此,当你分配了一个闭包给类实例的属性,并且闭包通过引用该实例或者它的成员来捕获实例,此时将会在闭包和实例之间产生循环引用

逃逸闭包 & 自动闭包

逃逸闭包

当闭包作为一个实际参数传递给一个函数的时候,并且它会在函数返回之后调用,我们就说这个闭包逃逸了

当你声明一个接收闭包作为形式参数的函数时,你可以在形式参数前面写@escaping来声明该闭包是允许逃逸的。

闭包可以逃逸的一种方法是将其存储在定义函数之外的变量里。比如说,很多函数接收闭包实际参数作为启动异步任务的回调,函数在启动任务后返回,但是闭包需要等到任务执行完毕之后才会被调用,此时该闭包需要逃逸,以便稍后调用。

需要注意的一点是:如果你让闭包@escaping,那么你就必须在闭包中显示地引用self,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func someFunctionWithEscapingClosure(closure: @escaping ()->Void) {    closure()}
func someFunctionWithNoneEscapingClosure(closure: ()->Void) {    closure()}
class SomeClass {    var x = 10        func doSomeThing() {        someFunctionWithEscapingClosure {            // 逃逸闭包中必须显示地引用self,否则会报错如下:            // Reference to property 'x' in closure requires explicit 'self.' to make capture semantics explicit            self.x = 100        }                someFunctionWithNoneEscapingClosure {            x = 200        }    }}

自动闭包

自动闭包是一种自动创建的闭包,用于包装作为实际参数传递给函数的表达式

自动闭包不接收任何的实际参数,当它被调用时,会返回内部包装的表达式的值

自动闭包语法的好处在于:通过写普通表达式代替显示闭包而使你省略包围函数形式参数的括号

Swift内部的assert函数里面就用到了自动闭包,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public func assert(_ condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String = String(), file: StaticString = #file, line: UInt = #line)

调用的时候直接写所要包装的表达式即可:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    var number = 3    assert(number > 3, "number不能大于3")

接下来我们看一段代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var names = ["mike", "norman", "lavie"]print(names.count) // 3
// removeOneName是一个闭包表达式,它可以被延迟处理let removeOneName = { names.removeFirst() }print(names.count) // 3
// 此时闭包表达式removeOneName会被执行print("Now remove \(removeOneName())") // Now remove mikeprint(names.count) // 2

上面代码中的,闭包的定义以及回调都可以封装到函数中,传一个闭包作为实际参数到函数的时候,会得到与延迟处理相同的行为,因此简化如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func removeName(waitingRemoveName: ()->String) {    print("Now remove \(waitingRemoveName())")}
var names = ["mike", "norman", "lavie"]print(names.count) // 3
removeName(waitingRemoveName: { names.removeFirst() }) // Now remove mikeprint(names.count) // 2

接下来我们就可以通过自动闭包的形式来简化上述代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func removeName(waitingRemoveName: @autoclosure()->String) {    print("Now remove \(waitingRemoveName())")}
var names = ["mike", "norman", "lavie"]print(names.count) // 3
removeName(waitingRemoveName: names.removeFirst()) // Now remove mikeprint(names.count) // 2

在函数removeName中,通过@autoclosure标志它的形式参数waitingRemoveName使用了自动闭包。这样,调用该函数的时候就好像接收了一个String类型的实参而不是闭包实际参数会被自动转换为闭包,因为waitingRemoveName形式参数的类型被标记为@autoclosure。

自动+逃逸

如果你想要自动闭包允许逃逸,那么你就可以同时使用@autoclosure和@escaping标志

函数式编程

题目一

首先从一道题目说起:

读入一个文本文件,确定该文件中所有单词的使用频率并从高到低进行排序,最后打印出所有单词及其频率的排序列表。

先来看一下我们熟悉的命令式(面向对象)解决方案:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let NON_WORDS = ["the", "and", "of", "to", "a", "i", "it", "in", "or", "is", "as", "so", "but", "be"]
func wordFreq(words: String) -> [String : Int] {    var wordDic: [String : Int] = [:]    let wordList = words.split(separator: " ")    for word in wordList {        let lowerCaseWord = word.lowercased() // 小写转换        if !NON_WORDS.contains(lowerCaseWord) { // 将不需要统计的筛选出去                        if let count = wordDic[lowerCaseWord] { // 统计出现次数                wordDic[lowerCaseWord] = count + 1            } else {                wordDic[lowerCaseWord] = 1            }        }    }        return wordDic}

let words = """There are moments in life when you miss someone so much that you just want to pick theme from your dreams and hug theme for real dream what you want to dream go where you want to go be what you want to be because you have only one life and one change to do all the things you want to do"""     print(wordFreq(words: words))//["where": 1, "there": 1, "are": 1, "from": 1, "that": 1, "things": 1, "what": 2, "someone": 1, "life": 2, "dreams": 1, "change": 1, "go": 2, "moments": 1, "only": 1, "do": 2, "just": 1, "you": 7, "dream": 2, "hug": 1, "all": 1, "have": 1, "much": 1, "when": 1, "miss": 1, "one": 2, "want": 5, "for": 1, "your": 1, "pick": 1, "real": 1, "because": 1, "theme": 2]

接下来对比看一下函数式的解决方案:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func wordFreq(words: String) -> [String : Int] {    var wordDic: [String : Int] = [:]    let wordList = words.split(separator: " ")        // 函数式解决方案    wordList.map({$0.lowercased()})        .filter({!NON_WORDS.contains($0)})        .forEach { (word) in            wordDic[word] = (wordDic[word] ?? 0) + 1    }        // 面向对象(命令式)解决方案//    for word in wordList {//        let lowerCaseWord = word.lowercased()//        if !NON_WORDS.contains(lowerCaseWord) {//            if let count = wordDic[lowerCaseWord] {//                wordDic[lowerCaseWord] = count + 1//            } else {//                wordDic[lowerCaseWord] = 1//            }//        }//    }        return wordDic}

现在来比较一下命令式和函数式这两种编程范式:

  • 命令式编程风格常常会迫使我们出于性能考虑,将不同的任务交织起来,以便能够用一次循环来完成多个任务;而函数式编程风格会用map、filter等高阶函数将我们解放出来,让我们站在更高的抽象层面上去考虑问题,将问题看得更清楚。
  • 面向对象编程通过封装不确定性因素来使代码能被人理解,他会把这些不确定性因素封装到类里面使人看不到;函数式编程通过尽量减少不确定因素来使代码能被人理解。在这一点上,后者更好一点,因为不确定因素本身是不容易被人理解的,应该越少越好,而不是封装起来进行隐藏更好。
  • 面向对象的命令式编程语言里面,重用的单元是类与类之间沟通用的消息函数式编程语言实现重用的思路很不一样,函数式编程语言提倡在有限的几种关键数据结构(如List、Set、Dictionary)上运用针对这些数据结构高度优化过得操作,以此构成基本的运转机构开发者再根据具体用途,插入自己的数据结构和高阶函数去调整机构的运转方式
  • 面向对象的命令式编程程序员喜欢不断创建新的数据结构和附属的操作,因为压倒一切的面向对象编程范式就是建立新的类和类之间的消息。把所有的数据结构都封装成类,一方面压制了方法层面的重用,另一方面鼓励了大粒度的框架式的重用。比起一味地创建新的类结构体系,把封装的单元降低到函数级别,更有利于达到细粒度的基础层面的重用函数式程序员喜欢用少数几个核心数据结构,围绕它们去建立一套充分优化的运转机构。函数式编程的程序构造更方便我们在比较细小的层面上重用代码。
  • 大部分的编程语言都是命令式的,程序员需要告诉代码先做什么、再做什么;而函数式编程会直接告诉程序员输出的结果是什么

也许,看完了上面的例子,你会有个疑问,函数式编程看着跟链式编程很像啊,两者是不是一个东西啊

实际上,函数式编程和链式编程完全不是一回事,函数式编程是一种编程思想,而链式编程仅仅是一种书写代码的方式。函数式编程是和面向对象的命令式编程并列的一种编程思想;而链式编程只要写起来是一个链条就可以,面向对象里你可以使用这种链的方式,函数式编程里也可以使用链式。

题目二

接下来我们通过另外一个题目来加深一下对函数式编程的理解:

现在有一个名字列表,其中一些条目由单个字符构成。任务是,将除去单字符条目之外的列表内容,放在一个逗号分割的字符串里返回,且每个名字的首字母都要大写。

首先来看一下命令式解法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func cleanNames(names: [String]) -> String {    var cleanNames = ""    for name in names {        if name.count > 1 {            cleanNames += name.capitalized + ","        }    }    cleanNames.remove(at: cleanNames.index(before: cleanNames.endIndex)) // 移除末尾多余的逗号        return cleanNames}

let employee = ["norman", "v", "lavie", "n", "mike", "lily", "zhangsan", "lisi", "wangwu", "w", "jackson", "jams"]print(cleanNames(names: employee)) // Norman,Lavie,Mike,Lily,Zhangsan,Lisi,Wangwu,Jackson,Jams

命令式编程是按照“程序是一系列改变状态的命令”来建模的一种编程风格。传统的for循环是命令式编程的绝好例子:先建立初始状态,然后每次迭代都会执行循环体中的一系列命令,进而改变初始状态

然后看一下函数式编程的解法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func cleanNames(names: [String]) -> String {    return names.filter({$0.count > 1})                .map({$0.capitalized})                .joined(separator: ",")}

函数式编程会将程序描述成表达式和变换,以数学方程的形式建立模型,并且尽量避免可变的状态。比如上例中,命令式解法中的cleanNames就是一种可变因素,而在函数式解法中是没有这个可变状态的,函数式是以表达式的形式对原数据进行操作和变换,期间没有不可变因素

函数式编程语言对问题的归类不同于命令式语言,如前面所用到的几种操作(map、filter等),每一种都作为一个逻辑分类由不同的函数所代表,这些函数实现了低层次的变换,然后开发者在开发的时候会根据业务需求定义更为高阶的函数来调整其低层次运转机构的运作。

函数式编程是一种编程范式,它提供给我们的编程元素就是函数在函数式编程中,函数是一等公民(first-class-citizen)。一等公民的意思就是:

  • 它可以按需创建
  • 它可以存储在数据结构中
  • 它可以当做实参传递给另一个函数
  • 它可以当作另一个函数的返回值

对象,是面向对象的命令式程序设计语言中的一等公民,它就满足所有上面的这些条件。在函数式编程语言里,函数就是一等公民。

函数式编程就是把函数当成是一个个的构造块,然后将这些函数组合起来,构造成一个新的构造块。

说得更白话一点,程序无非就是多个构造块的组合,只不过面向对象编程的基础组件是类,而函数式编程的基础组件是函数

函数式编程的组合性

在函数式编程中,有一类特殊的函数,它们可以接收函数作为输入,或者返回一个函数作为输出。这种函数叫做高阶函数。这类似于高中数学中的复合函数的概念,也就是f(g(x))。

高阶函数有啥用呢?它的一个重要的作用在于,我们可以使用高阶函数去做行为的组合

按照函数式编程的理念,提供者提供的是一个又一个的构造块,即一个又一个函数,然后使用者根据自己的需要进行组合。模型提供者提供出来的是一个又一个的构造块,以及它们的组合方式。使用者根据自己的需要将这些构造块组合起来,提供出新的模型,供其他开发者使用。就这样,模型之间一层又一层地逐步叠加,最终构建起我们的整个应用。

一个好模型的设计就应该是逐层叠加。函数式编程的组合性,就是一种好的设计方式。

面向对象编程也有组合的概念,只不过面向对象中组合的元素是类和对象,而函数式编程组合的是函数。

在实际工作中,我们可以将面向对象和函数式这两种不同的编程范式进行组合运用:用面向对象编程的方式对系统的结构进行搭建,然后,用函数式编程的理念对函数接口进行设计

函数式编程的不变性

函数式编程的不变性主要体现在值和纯函数上。

值,你可以将它理解成一个初始化之后就不再改变的量,换句话说,当你使用一个值的时候,值是不会变的。

纯函数,是符合下面两点的函数:

  • 对于相同的输入,给出相同的输出
  • 没有副作用

把值和纯函数结合起来看,值保证不会显示改变一个量,而纯函数保证的是,不会隐式改变一个量

我们知道,函数式编程中的函数一词可以理解成是数学中的函数。在这个语境中,函数就是纯函数,一个函数计算之后是不会产生额外的改变的,而函数中用到的一个一个量就是值,他们是不会随着计算改变的。所以,在函数式编程中,计算天然就是不变的。

编写纯函数的重点是,不修改任何字段,也不调用修改字段内容的方法

还有一个实用性的编程建议是,要多从不变的角度思考问题,尽量使用语法中不变的修饰符,比如Swift中的let。

不过,纯粹的函数式编程是很困难的,我们只能把编程原则设定为:尽可能编写不变类和纯函数

现在纯函数式的语言适用范围并不广泛,但是越来越多的语言支持了函数式编程,比如Swift、Java

以上。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 iOS小生活 微信公众号,前往查看

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Swift3.0带来的变化汇总系列三——函数和闭包写法上的微调
    Swift3.0相比Swift2.2的版本在API上做了大量的修改,代码风格也更加统一。在函数方面,Swift3.0中做的最大修改是修改了内部名称与外部名称的默认规则。
珲少
2018/08/15
5140
Swift教程(七)--闭包
闭包是可以在你的代码中被传递和引用的功能性独立模块。Swift 中的闭包和 C 以及 Objective-C 中的 blocks 很像,还有其他语言中的匿名函数也类似。
roc
2019/07/31
7850
Swift基础 嵌套
翻译自:https://docs.swift.org/swift-book/LanguageGuide/Closures.html#ID102
郭顺发
2023/07/17
2230
iOS面试题-Swift篇
面试题持续整理更新中,如果你正在面试或者想一起进阶,不妨添加一下交流群 1012951431一起交流。
会写bug的程序员
2020/06/28
3.7K0
iOS面试题-Swift篇
swift底层探索 09 - Block捕获外界变量原理swift底层探索 09 - Block捕获外界变量原理
本文中分析两个问题: 1. Block闭包是一个引用类型 2. Block捕获外部变量
用户8893176
2021/08/09
7960
swift底层探索 09 - Block捕获外界变量原理swift底层探索 09 - Block捕获外界变量原理
Swift之闭包
Swift 是一门由Apple 公司开发的用于iOS和OSX设备上的开发语言,吸收了很多现代开发语言的优势。 今天看了官方的关于闭包部分的文档,感觉很不错,记录一下。
EltonZheng
2021/01/26
1.7K0
通过Swift学函数式编程
在文章SWIFT IS A LOT LIKE SCALA [1] 提到Swift和Scala有很大的相似之处,在某些特性甚至比Scala对函数式编程的支持更友好。笔者遂从Swift语言出发,学习函数式编程[2] [3],并记录笔记如下。
刘笑江
2018/05/28
7692
14.闭包
闭包引入 计算1个数的平方 函数写法 func square(param:Int) -> Int{ return param * param } square(param:3) 闭包写法 let squareCloure = { (param:Int) -> Int in return param * param } squareCloure(3) 闭包含义 闭包是可以被传递和引用的一个独立模块 闭包能够捕获和存储定义在其上下文中的任何常量和变量,即闭合并包裹那些常量和变量,因此被称为
YungFan
2018/10/11
8130
Swift学习:闭包
本篇将详细总结介绍Swift闭包的用法; 闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift中的闭包与C和 Objective-C中的代码块(blocks)以及其他一些编程语言中的匿名函数比较相似。
梧雨北辰
2018/08/09
8970
【面试必备】Swift 面试题及其答案
答案:optional 类型被用来表示任何类型的变量都可以表示缺少值。在 Objective-C 中,引用类型的变量是可以缺少值,并且使用 nil 作为缺少值。基本的数据类型如 int 或者 float 没有这种功能。
Swift社区
2021/11/26
7K0
Python深入04 闭包
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢! 闭包(closure)是函数式编程的重要的语法结构。函数式编程是一种编程范式 (而面向过程编程和面向对象编程也都是编程范式)。在面向过程编程中,我们见到过函数(function);在面向对象编程中,我们见过对象(object)。函数和对象的根本目的是以某种逻辑方式组织代码,并提高代码的可重复使用性(reusability)。闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性。 不同的
Vamei
2018/01/18
6120
Swift系列八 - 闭包
要想使用exec函数,则必须传入两个Int类型的参数和一个返回Int类型的函数,然后exec内部执行了传入的函数。
呆呆
2021/05/27
4370
Swift基础语法(二)
我们之前介绍的数组Array、字典Dictionary等,都是值类型,而函数是引用类型。
拉维
2020/06/02
2.3K0
Python——带你五分钟了解函数式编程与闭包
函数式编程这个概念我们可能或多或少都听说过,刚听说的时候不明觉厉,觉得这是一个非常黑科技的概念。但是实际上它的含义很朴实,但是延伸出来许多丰富的用法。
TechFlow-承志
2020/04/15
5370
Swift进阶一:Swift简介
Swift语言引入了协议、协议的扩展、泛型等新特性,因此使用Swift语言可以很好地面向协议编程;Swift语言将函数和闭包提升为语言的一等公民,函数可以作为一个变量、可以作为其他函数的参数、作为其他函数的返回值等来传递,所以我们可以使用Swift来进行函数式编程,另外Swift也提供了很多高阶函数来辅助我们进行函数式编程;Swift也提供了属性的权限限定等面向对象的基础设置,因此在Swift中也可以面向对象来编程。
拉维
2020/07/09
2.9K0
Swift进阶一:Swift简介
Swift3.0 - 函数和闭包
需求: 创建一个接口,输入true 返回 两个数相加的函数,输入false 返回两个数相减的函数
酷走天涯
2018/09/14
1.2K0
Swift3.0 - 函数和闭包
聊聊Go里面的闭包
以前写 Java 的时候,听到前端同学谈论闭包,觉得甚是新奇,后面自己写了一小段时间 JS,虽只学到皮毛,也大概了解到闭包的概念,现在工作常用语言是 Go,很多优雅的代码中总是有闭包的身影,看来不了解个透是不可能的了,本文让我来科普(按照自己水平随便瞎扯)一下:
秦怀杂货店
2022/11/21
2930
swift 闭包(闭包表达式、尾随闭包、逃逸闭包、自动闭包)
下面例子通过使用几次迭代展示了 sorted(by:)方法的定义和语法优化的方式。每一次迭代都用更简洁的方式描述了相同的功能
xy_ss
2023/11/22
8440
Swift讲解专题八——闭包 原
        Swift中的闭包是有一定功能的代码块,这十分类似于Objective-C中的block语法。Swift中的闭包语法风格十分简洁,其作用和函数的作用相似。
珲少
2018/08/15
3990
Python学习笔记九(变量作用域及内置函数和闭包函数)
在上次的学习中,初步认识了Python的自定义函数方式及变量参数。那么编程中的局部变量和全局变量应该是大多数语言的标配。Python中如果定义局部变量和全局变量的呢?在编程思想中无论是面向对象还是面向过程,都逃不开函数,函数中嵌套函数,这样的典型函数式编程对内嵌函数和闭包函数的支持是如何操作的呢?
世纪访客
2018/08/02
4230
Python学习笔记九(变量作用域及内置函数和闭包函数)
相关推荐
Swift3.0带来的变化汇总系列三——函数和闭包写法上的微调
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验