meg*_*gri 11 scala standard-library keyword lazy-evaluation
Scala在其标准库中保留了许多非常有用的构造,如Option和Try.
当缺少上述类型的C#等语言选择将其作为库功能实现时,为什么懒惰通过拥有自己的关键字给予特殊处理?
0__*_*0__ 15
确实可以定义一个惰性值,例如:
object Lazy {
def apply[A](init: => A): Lazy[A] = new Lazy[A] {
private var value = null.asInstanceOf[A]
@volatile private var initialized = false
override def toString =
if (initialized) value.toString else "<lazy>@" + hashCode.toHexString
def apply(): A = {
if (!initialized) this.synchronized {
if (!initialized) {
value = init
initialized = true
}
}
value
}
}
implicit def unwrap[A](l: Lazy[A]): A = l()
}
trait Lazy[+A] { def apply(): A }
Run Code Online (Sandbox Code Playgroud)
用法:
val x = Lazy {
println("aqui")
42
}
def test(i: Int) = i * i
test(x)
Run Code Online (Sandbox Code Playgroud)
另一方面,具有lazy作为语言提供的修饰符具有允许其参与统一访问原则的优点.我试图查找一个博客条目,但没有任何超越getter和setter.这个原则实际上更为基础.对于值,以下是统一的:val,lazy val,def,var,object:
trait Foo[A] {
def bar: A
}
class FooVal[A](val bar: A) extends Foo[A]
class FooLazyVal[A](init: => A) extends Foo[A] {
lazy val bar: A = init
}
class FooVar[A](var bar: A) extends Foo[A]
class FooProxy[A](peer: Foo[A]) extends Foo[A] {
def bar: A = peer.bar
}
trait Bar {
def baz: Int
}
class FooObject extends Foo[Bar] {
object bar extends Bar {
val baz = 42
}
}
Run Code Online (Sandbox Code Playgroud)
在Scala 2.6中引入了惰性值.有一个Lambda终极评论表明推理可能与形式化循环引用的可能性有关:
循环依赖关系需要与惰性值绑定.延迟值还可用于强制按依赖顺序进行组件初始化.遗憾的是,组件关闭顺序必须手动编码
我不知道为什么编译器无法自动处理循环引用; 也许有复杂性或表现性的原因.一个博客帖子是Iulian Dragos的证实一些假设.
Rüd*_*ehn 10
当前的延迟实现使用int位掩码来跟踪字段是否已初始化,并且没有其他内存开销.该字段在多个惰性val之间共享(每个字段最多32个惰性值).实现具有与库特征类似的存储器效率的特征是不可能的.
作为库的懒惰可能看起来大致如下:
class LazyVal[T](f: =>T) {
@volatile private var initialized = false
/*
this does not need to be volatile since there will always be an access to the
volatile field initialized before this is read.
*/
private var value:T = _
def apply() = {
if(!initialized) {
synchronized {
if(!initialized) {
value = f
initialized = true
}
}
}
value
}
}
Run Code Online (Sandbox Code Playgroud)
这的开销将是生成值的闭包f的对象,以及LazyVal本身的另一个对象.因此,对于经常使用的功能来说,这将是很重要的.
在CLR上你有值类型,所以如果在C#中将LazyVal实现为struct,那么开销就不那么糟了
但是,现在宏可用,将惰性转换为库特征或至少允许自定义延迟初始化可能是个好主意.许多lazy val的使用情况不需要线程同步,因此每次使用lazy val时都要浪费@ volatile/synchronized开销.
| 归档时间: |
|
| 查看次数: |
476 次 |
| 最近记录: |