kotlin之闭包案例详解

闭包,函数式编程福音

先了解函数式编程(Functional Programming)

概念:它属于“结构化编程”的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用。函数式编程语言最重要的基础是λ运算(Lambda表达式),λ运算的函数可以接受函数当做参数或返回值。

对比函数式编程与面向对象编程

面向对象编程(Object-oriented programming,缩写OOP)

面向对象编程是一种具有对象概念的程序编程范型,它可能包含数据、属性、方法。它将对象作为程序的基本单元,将方法和数据封装其中,以提高软件的重用性、灵活性和扩展性。对象里的程序可以访问及经常修改对象相关联的数据。在面向对象编程里,计算机程序会被设计成彼此相关的对象。

面向对象编程的优点

1.程序的结构化

面向对象程序设计可以看作一种在程序中包含各种独立而又互相调用的对象的思想,相比传统的面向过程编程将程序看作一系列函数的集合这种无系统化和结构化的模式,面向对象编程将一系列关联性的数据、方法结构化,封装成类,通过类的对象进行方法、属性调用的方式,可以让编程者更加便于分析、设计和理解。

2.程序的灵活性和可维护性

面向对象编程由于集成、封装、多态的特性,可以更好的设计出高内聚、低耦合的系统 结构,使得系统更灵活、更容易扩展,开发及维护成本更低。

面向对象编程的缺点

  1. 运行效率较低
    面向对象虽然开发效率高但是代码运行效率比起面向过程要低很多,这也限制了面向对象的使用场景不能包括那些对性能要求很苛刻的地方
  2. 多线程数据不安全
    面向对象编程以数据为核心,所以在多线程并发编程中,多个线程同时操作数据的时候可能会导致数据修改的不确定性。

函数式编程优点(可以说就是为了解决面向对象的缺点问题而设计的)

  1. 线程安全
    在函数式编程中,数据全部都是不可变的,所以没有并发编程的问题,是多线程安全的,可以有效降低程序运行中所产生的副作用。对于快速迭代的项目来说,函数式编程可以实现函数与函数之间的热切换而不用担心数据的问题,因为它是以函数作为最小单位的,只要函数与函数的关系正确即可保证结果的正确性。
  2. 代码可读性高
    函数式编程的表达方式更加符合人类日常生活中的语法,代码可读性更强。实现同样的功能函数式编程所需要的代码比面向对象编程要少很多,代码更加简洁明晰。

函数式编程的缺点

运行速度更慢
由于所有的数据都是不可变的,所有的变量在程序运行期间都是一直存在的,非常占用运行资源。同时由于函数式的先天性设计导致性能一直不够。虽然现代的汗水编程语言使用了很多技巧,比如惰性计算等优化运行速度,但始终无法与面向对象相比,当然比面向过程的程序就更慢了

了解完函数式编程,再回归今天的主题——闭包

什么是闭包?

我们都知道,程序的变量分为全局变量局部变量,全局变量,顾名思义,其作用域是当前文件甚至文件外的所有地方;而局部变量,我们只能再其有限的作用域里获取。
那么,如何在外部调用局部变量呢?答案就是——闭包,与此给闭包下个定义:闭包就是能够读取其他函数内部变量的函数

  • 它是运行的环境
  • 它持有函数的运行状态
  • 它的内部可以定义函数
  • 它的内部也可以定义类

首先看个简单的例子

//这是一个返回值为一个函数的高阶函数
fun makeFun():()->Unit{
    var conut = 0
    return fun(){   //返回一个匿名函数,这个函数持有count的状态
        println(++conut)
    }
}

fun main() {

    val makeFun = makeFun() //函数调用,返回一个函数
    makeFun()       //调用这个返回的函数,此时makeFun持有makeFun()内部变量的状态
    makeFun()
    makeFun()
}

运行结果:

在比如一个稍微复杂一点的例子,实现斐波那契数列

//斐波那契数列
fun fibonacci():()->Long{
    var first = 0L
    var second = 1L
    return fun():Long{  //返回返回值为Long类型的函数
        val result = second
        second += first
        first = second - first
        return result
    }
}

fun main() {
    val fibo = fibonacci()	//此时,这个返回的函数fibo持有fibonnacci()函数内部变量的状态
    println(fibo())
    println(fibo())
    println(fibo())
    println(fibo())
    println(fibo())
}

测试运行:

使用迭代器实现斐波那契数列

//使用迭代器实现斐波那契数列(这里就不是返回一个函数而是一个对象了)
fun fibonacci2():Iterable<Long>{
    var first = 0L
    var second = 1L
    return Iterable {
        object :LongIterator(){
            override fun hasNext() = true

            override fun nextLong(): Long {
                val result = second
                second += first
                first = second - first
                return result
            }

        }
    }
}
fun main() {
    val fibo2 = fibonacci2()
    for (i in fibo2){
        if (i>60) break
        println(i)
    }
}

运行结果:

到此这篇关于kotlin之闭包案例详解的文章就介绍到这了,更多相关kotlin之闭包内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android使用Kotlin API实践WorkManager

    WorkManager 提供了一系列 API 可以更加便捷地规划异步任务,即使在应用被关闭之后或者设备重启之后,仍然需要保证立即执行的或者推迟执行的任务被正常处理.对于 Kotlin 开发者,WorkManager 为协程提供了最佳的支持.在本文中,我将通过实践 WorkManager codelab 为大家展示 WorkManager 中与协程相关的基本操作.那么让我们开始吧! WorkManager 基础 当您需要某个任务保持运行状态,即使用户切换到别的界面或者用户将应用切换到后台,甚至设备

  • Kotlin中?和!!的区别详细对比

    前言 很多同学刚上手使用Kotlin知道它有针对Java NullPointerException的管理,而在Kotlin中?和!!均是和NullPointerException有关系,可他们的区别到底是什么呢?为什么别人开发的项目中出现了好多"?",而我读起来却满脸问号. 不懂就问百度呀,确实有人解释它们的区别,比如: 这是输入"kotlin ?和!!"搜索到的百度第一条答案,确实这位说的没错.不过我觉得对于一个刚接触KT(Kotlin)的新手来说,他恐怕需要有汉

  • Kotlin + Flow 实现Android 应用初始化任务启动库

    特性 Kotlin + Flow 实现的 Android 应用初始化任务启动库. 支持模块化,按模块加载任务 可指定工作进程名称,main 表示仅在主进程运行,all 表示在所有进程运行,默认值all 可指定任务仅在工作线程执行 可指定任务仅在调试模式执行 可指定任务在满足合规条件后执行 可指定任务优先级,决定同模块内无依赖同步任务的执行顺序 可指定依赖任务列表,能检测循环依赖 使用 Flow 调度任务 仅200多行代码,简单明了 有耗时统计 引入依赖 项目地址:github.com/czy11

  • Kotlin中日志的使用方法详解

    1 引言 想必学过Java的人都知道一个@Slf4j使用得多么的舒服: @Slf4j public class TestController{ @GetMapping("/test") public String test(){ log.debug("debug"); return "test"; } } 但是很不幸在Kotlin中并没有这种注解,因此,本文给出了一种类似@Slf4j注解在Kotlin中的使用方法,以及介绍一个100%使用Kotl

  • Kotlin协程到底是如何切换线程的

    随着kotlin在Android开发领域越来越火,协程在各个项目中的应用也逐渐变得广泛 但是协程到底是什么呢? 协程其实是个古老的概念,已经非常成熟了,但大家对它的概念一直存在各种疑问,众说纷纷 有人说协程是轻量级的线程,也有人说kotlin协程其实本质是一套线程切换方案 显然这对初学者不太友好,当不清楚一个东西是什么的时候,就很难进入为什么和怎么办的阶段了 本文主要就是回答这个问题,主要包括以下内容 1.关于协程的一些前置知识 2.协程到底是什么? 3.kotlin协程的一些基本概念,挂起函数

  • Kotlin线程同步的几种实现方法

    目录 1. Thread.join() 2. Synchronized 3. ReentrantLock 4. BlockingQueue 5. CountDownLatch 6. CyclicBarrier 7. CAS 8. Future 9. CompletableFuture 10. RxJava 11. Coroutine 12. Flow 总结 面试的时候经常会被问及多线程同步的问题,例如: " 现有 Task1.Task2 等多个并行任务,如何等待全部执行完成后,执行 Task3.

  • kotlin之闭包案例详解

    闭包,函数式编程福音 先了解函数式编程(Functional Programming) 概念:它属于"结构化编程"的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用.函数式编程语言最重要的基础是λ运算(Lambda表达式),λ运算的函数可以接受函数当做参数或返回值. 对比函数式编程与面向对象编程 面向对象编程(Object-oriented programming,缩写OOP) 面向对象编程是一种具有对象概念的程序编程范型,它可能包含数据.属性.方法.它将对象作为程序的基本单元,

  • Android Kotlin使用SQLite案例详解

    Kotlin使用SQLite 首先确定我们的目标,SQLite只是一种工具,我们需要掌握就是增删改查就可以,我们真正需要动脑的还是项目中的业务逻辑.我这篇文章写得比较适合新手,没用过SQLite的同学. 前期准备工作 新建一个类MyDataBaseHelper继承自SQLiteOpenHelper,代码如下: class MyDatabaseHelper(var context: Context, name: String, version: Int) : SQLiteOpenHelper(co

  • Python 中闭包与装饰器案例详解

    项目github地址:bitcarmanlee easy-algorithm-interview-and-practice 1.Python中一切皆对象 这恐怕是学习Python最有用的一句话.想必你已经知道Python中的list, tuple, dict等内置数据结构,当你执行: alist = [1, 2, 3] 时,你就创建了一个列表对象,并且用alist这个变量引用它: 当然你也可以自己定义一个类: class House(object): def __init__(self, are

  • Kotlin常用函数let,with,run,apply用法与区别案例详解

    在kotlin编程中let.with.run.apply这些函数使用率是非常高的,有时候可以通用,差别很小,但如果能记住他们的不同点,可以更加合理的选择使用. 在这之前首先要了解一下Lambda表达式的一些规则,这会帮助你理解使用这些函数的时候有没有( )可不可以用it代替参数等.因为这些函数的最后一个参数都是lambda. 如何理解lambda呢?可以把lambda理解为就是一个对象,但这个对象比较特殊,它是一段代码,既然是对象就可以作为函数的参数使用.这种对象称为函数对象. lambda表达

  • Kotlin修饰符lateinit(延迟初始化)案例详解

    Kotlin定义变量一般有如下写法 lateinit var name: String var age: String? = null 那么用lateinit 修饰和下面那种有什么区别呢,我们来看一下这两行代码反编译成java代码是什么样子的. @NotNull public String name; @Nullable private String age; @NotNull public final String getName() { String var10000 = this.name

  • Kotlin lateinit与by lazy案例详解

    lateinit 和 lazy 是 Kotlin 中的两种不同的延迟初始化的实现 lateinit 只用于变量 var,而 lazy 只用于常量 val lazy 应用于单例模式(if-null-then-init-else-return),而且当且仅当变量被第一次调用的时候,委托方法才会执行. lazy()是接受一个 lambda 并返回一个 Lazy <T> 实例的函数,返回的实例可以作为实现延迟属性的委托: 第一次调用 get() 会执行已传递给 lazy() 的 lambda 表达式并

  • Python中return用法案例详解

    python中return的用法 1.return语句就是把执行结果返回到调用的地方,并把程序的控制权一起返回 程序运行到所遇到的第一个return即返回(退出def块),不会再运行第二个return. 例如: def haha(x,y): if x==y: return x,y print(haha(1,1)) 已改正: 结果:这种return传参会返回元组(1, 1) 2.但是也并不意味着一个函数体中只能有一个return 语句,例如: def test_return(x): if x >

  • IOS之WebSocket框架Starscream案例详解

    传统的网络技术 (也就是 Berkeley sockets) 被认为是可靠和稳定的.但是 Berkeley socket 在某些 web 技术,比如代理和防火墙下不太好使.WebSocket 出现于 2011 年,是一种在客户端和服务端之间建立双向通讯的新技术.WebSocket 比起多个 HTTP 请求来说更有效率并允许长连接. 在 iOS 上使用 WebSocket 并不是那么容易.iOS 和 Mac 库 Starscream 的出现,极大地简化了 WebSocket 的创建和使用. 注:本

  • Js类的构建与继承案例详解

    JS里类的定义和继承实在五花八门,所以单独开一个笔记本记录. 定义 派生于Object的方式 1.new Object:在创建对象后动态定义属性.方法 var Car = new Object; Car.color = "red"; Car.showColor = function(){ console.log(this.color); } //想要继承就要先构造空对象然后用__proto__原型链来继承 var Car1 = new Object; //或者 = {} Car1.__

  • Vue中watch清除过期副作用的案例详解

    在这里就不过多说watch的用法了,主要了解一下如何清除过期的副作用 通过一个案例来说吧: 一个可搜索的下拉选择器,用户第一次进行搜索的时候网速比较慢,请求虽然被服务端正确响应了,但是数据一直没有传输到客户端,用户看下拉数据没变化 就第二次搜索.第二次搜索之后网速恢复正常了,第二次请求的数据很快就客户端接收且正确渲染:紧接着第一次的数据也被客户端接收且客户端正确渲染. 这样就可能存在这样一种情况,第一次请求,服务端响应了请求但数据还没被客户端接收的时候,有人修改了数据:然后用户又点击刷新,响应数

随机推荐