Scala中的延迟初始化(Lazy vals)
延迟初始化(Lazy vals)
除了前面介绍的预先初始化成员值外,你还是让系统自行决定何时初始化成员的初始值,这是通过在 val 定义前面添加 lazy(懒惰),也是说直到你第一次需要引用该成员是,系统才会去初始化,否则该成员就不初始化(这也是 lazy 的由来:-)).首先我们定义一个正常定义 val 的例子:
object Demo {val x = { println("initializing x"); "done"}
}
我们首先引用 Demo,然后 Demo.x
scala> Demo
initializing x
res0: Demo.type = Demo$@78178c35scala> Demo.x
res1: String = done
正如你所看到的,当引用 Demo 对象时,它的成员 x 也会初始化,初始化 x 伴随着初始化 Demo 的过程。然后,如果我们在 val x 前添加 lazy ,情况就有所不同了:
object Demo {lazy val x = { println("initializing x"); "done"}
}defined object Demoscala> Demo
res0: Demo.type = Demo$@7de1c412scala> Demo.x
initializing x
res1: String = done
在使用 lazy 之后,初始化 Demo 时,不会初始化 x,只有在引用到 Demo.x 该初始化代码才会执行。这有点类似定义了一个无参数的方法,但和 def 不同的是,lazy 变量初始化代码只会执行一次。通过这个例子,我们可以看到例如 Demo 的对象本身也像一个 lazy 变量,也是在第一次引用时才会初始化,这是正确的,实际上一个 object 定义可以看成是使用了lazy val定义一个匿名类实例的简化方式。
使用l azy val,我们可以修改之前的 RationalTrait, 在这个新的 Trait 定义中,所有的类成员变量的实现(非抽象成员)都使用 lazy 来修饰。
trait LazyRationalTrait{val numerArg :Intval denomArg :Intlazy val numer = numerArg/glazy val denom = denomArg/gprivate lazy val g = {require(denomArg !=0)gcd(numerArg,denomArg)}private def gcd(a:Int,b:Int):Int =if(b==0) a else gcd(b, a % b)override def toString = numer + "/" + denom
}
同时我们把 require 移动到 g 里面,这样所有的 lazy val 初始化代码都移动到 val 定义的右边。我们不再需要预先初始化成员变量。测试如下:
scala> val x = 2
x: Int = 2scala> new LazyRationalTrait{val numerArg = xval denomArg = 2 * x
}res2: LazyRationalTrait = 1/2
我们来分析一下这段代码中命令行的执行顺序:
- 首先,创建了一个新的 LazyRationalTrait 的实例,执行 LazyRationalTrait 的初始化代码,这部分代码为空,LazyRationalTrait 所有成员变量都没有初始化。
- 其次,该 Trait 的匿名子类的主构造函数被执行,这部分初始化 numberArg 和 denomArg 为2和4.
- 接下来,命令行需要调用该实例的 toString 方法来显示该实例的值。
- 接下来,toString 需要访问成员 number 这是第一次访问该成员,因此 lazy val 初始化代码被执行。初始化代码调用私有成员g,因此需要计算 g 的值,用到之前定义过的 numberArg 和 denomArg。
- 接下来 toString 需要访问成员 denom 这是第一次访问该成员,因此 lazy val 初始化代码被执行。初始化代码调用私有成员 g ,因此需要计算 g 的值,因为 g 已经计算过,无需再计算。
- 最后,toString 的结果1/2构造出来并显示。
在这个例子中,我们在写代码时,g 定义在 number 和 denom 的后面,然而,由于这三个变量都是使用 lazy 来定义的,因此它们在代码中出现的顺序并不重要。
Scala中的延迟初始化(Lazy vals)相关推荐
- java并发中的延迟初始化
不安全的延迟初始化示例: Java代码 public class UnsafeLazyInitialization { private static Resource resource; publ ...
- 【CSharp】延迟初始化(Lazy)
参考 https://www.jb51.net/article/202143.htm 1. 什么是延迟初始化 延迟初始化是一种将对象的创建延迟到第一次需要用时的技术,换句话说,对象的初始化是发生在真正 ...
- 合理利用延迟初始化优化 Spring Boot
点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源 | 公众号「码农小胖哥」 1. 前言 随着我们项目 ...
- Kotlin实战指南九:延迟初始化
转载请标明出处:https://blog.csdn.net/zhaoyanjun6/article/details/93764289 本文出自[赵彦军的博客] 高阶函数 lateinit 延迟初始化 ...
- java 延迟初始化_Java - 延迟初始化
延迟初始化(lazy initialization),也就是在真正被使用的时候才开始初始化的技巧. 不论是静态还是实例,都可以进行延迟初始化. 其本质是初始化开销和访问开销之间的权衡. 毕竟是一种优化 ...
- Spring:延迟初始化
ApplicationContext实现的默认行为就是在启动时将所有singleton bean提前进行实例化.提前实例化意味着作为初始化过程的一部分,ApplicationContext实例会创建并 ...
- spring的延迟初始化bean (default-lazy-init 与 lazy-init )
ApplicationContext实现的默认行为就是在启动时将所有singleton bean提前进行实例化.提前实例化意味着作为初始化过程的一部分,ApplicationContext实例会创建并 ...
- scala学习笔记-过程、lazy值和异常(6)
过程 在Scala中,定义函数时,如果函数体直接包裹在了花括号里面,而没有使用=连接,则函数的返回值类型就是Unit.这样的函数就被称之为过程.过程通常用于不需要返回值的函数. 过程还有一种写法,就是 ...
- 【Kotlin】属性 与 幕后字段 ( 属性声明 | 属性初始化器 | 属性访问器 | field 属性幕后字段 | lateinit 延迟初始化属性 )
文章目录 I . 属性 字段 总结 II . 属性声明 III . 属性初始化器 IV . get / set 属性访问器 V . 属性幕后字段 field VI . 变量和常量的区别 VII . 延 ...
最新文章
- Linux下的内存对齐函数
- Docker Compose 配置文件详解
- 由浅入深:自己动手开发模板引擎——解释型模板引擎
- 解决ubuntu软件安装依赖关系
- 51CTO大赛,欢迎投博主一票
- 需要使用Git branch switch 的情况Git stash的使用时机
- STM8S——watchdog(IWDG)
- js一键批量打印_JS 实现选中内容批量打印/导出
- html 设置origin,background-origin属性怎么用
- uniapp 复制剪贴板
- 裁员潮来袭,如何度过这两年“艰苦岁月”
- 机器学习项目一:共享单车
- 证件照背景色怎么换白色?这两个小技巧要掌握
- 基于Pubmed数据库的蛋白质修饰后的信息挖掘
- 学生成绩管理系统 ssm layui
- [渝粤教育] 广东-国家-开放大学 21秋期末考试大学英语210262k2 (2)
- 联接+AI,华为用智能联接为智能时代加速
- 单片机学习笔记 —— 8位数码管动态扫描
- 安超云生态 | 安超云与百信完成产品兼容互认证 携手打造协同生态
- 数据安全平台建设思路
热门文章
- id int primary key auto_increment是什么意思
- (*长期更新)软考网络工程师学习笔记——Section 10 网络安全
- js微信抢红包脚本代码_使用AutoJs实现微信抢红包的代码
- flask执行python脚本_如何在Flask中运行python脚本
- STM32 ADC采样使用内部参考电压
- mysql 优化器不准_mysql 优化器有哪些可选开关
- css画带边框三角形,纯CSS画三角形(带边框)
- word域变成正常文本_word文档中打钩的8种方法!(全网最全)
- 管理服务器一般的作用,管理服务器作用
- 跑python gpu利用率低_训练效率低?GPU利用率上不去?快来看看别人家的tricks吧~...