为什么case类的每个新实例都会在Scala中再次评估懒惰的val? [英] Why do each new instance of case classes evaluate lazy vals again in Scala?

查看:128
本文介绍了为什么case类的每个新实例都会在Scala中再次评估懒惰的val?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据我的理解,scala将val定义视为值。
因此,具有相同参数的案例类的任何实例都应该是相等的。
但是,

  case class A(a:Int){
lazy val k = {
println(k)
1
}

val a1 = A(5)
println(a1.k)
输出:
k
res1:Int = 1

println(a1.k)
输出:
res2:Int = 1

val a2 = A(5)
println(a1.k)
输出:
k
res3:Int = 1

我期待着println(a2.k),它不应该打印k。
因为这不是必需的行为,所以我应该如何实现这个,以便对于具有相同参数的case类的所有实例,它只应该只执行一次lazy val定义。需要一些memoization技术或斯卡拉可以自己处理这个?



我对Scala和函数式编程非常新,所以请原谅我,如果你发现问题微不足道。假设你不重写 equals 或者做一些不明智的事情使构造函数参数 var s,则具有相同构造函数参数的两个case类实例化将相等。但是, not 意味着具有相同构造函数参数的两个case类实例将指向内存中的相同对象

  case class A(a:Int)
A(5)== A(5)// true,与'A(5).equals(A 5))
A(5)eq A(5)// false

如果你希望构造函数总是在内存中返回相同的对象,那么你需要自己处理它。也许使用某种工厂:

  case class private(a:Int){
lazy val k = {
println(k)
1
}
}

对象A {
private [this] val cache = collection.mutable .Map [Int,A]()
def build(a:Int)= {
cache.getOrElseUpdate(a,A(a))
}
}

val x = A.build(5)
xk //打印k
val y = A.build(5)
yk //不打印任何东西
x == y // true
x eq y // true

你不关心构造函数返回相同的对象,但你只关心 k 的重新评估,你可以缓存该部分:

  case class A(a:Int){
lazy val k = A.kCache.getOrElseUpdate(a,{
println (k)
1
})
}

对象A {
private [A] val kCache = collection.mutable.Map [Int ,Int]()
}

A(5).k //打印k
A(5).k //不显示任何内容


From what I have understood, scala treats val definitions as values. So, any instance of a case class with same parameters should be equal. But,

case class A(a: Int) {
   lazy val k = {
       println("k")
       1
   }

 val a1 = A(5)
 println(a1.k)
 Output:
 k
 res1: Int = 1

 println(a1.k)
 Output:
 res2: Int = 1

 val a2 = A(5)
 println(a1.k)
 Output:
 k
 res3: Int = 1

I was expecting that for println(a2.k), it should not print k. Since this is not the required behavior, how should I implement this so that for all instances of a case class with same parameters, it should only execute a lazy val definition only once. Do I need some memoization technique or Scala can handle this on its own?

I am very new to Scala and functional programming so please excuse me if you find the question trivial.

解决方案

Assuming you're not overriding equals or doing something ill-advised like making the constructor args vars, it is the case that two case class instantiations with same constructor arguments will be equal. However, this does not mean that two case class instantiations with same constructor arguments will point to the same object in memory:

case class A(a: Int)
A(5) == A(5)  // true, same as `A(5).equals(A(5))`
A(5) eq A(5)  // false

If you want the constructor to always return the same object in memory, then you'll need to handle this yourself. Maybe use some sort of factory:

case class A private (a: Int) {
  lazy val k = {
    println("k")
    1
  }
}

object A {
  private[this] val cache = collection.mutable.Map[Int, A]()
  def build(a: Int) = {
    cache.getOrElseUpdate(a, A(a))
  }
}

val x = A.build(5)
x.k                  // prints k
val y = A.build(5)
y.k                  // doesn't print anything
x == y               // true
x eq y               // true

If, instead, you don't care about the constructor returning the same object, but you just care about the re-evaluation of k, you can just cache that part:

case class A(a: Int) {
  lazy val k = A.kCache.getOrElseUpdate(a, {
    println("k")
    1
  })
}

object A {
  private[A] val kCache = collection.mutable.Map[Int, Int]()
}

A(5).k     // prints k
A(5).k     // doesn't print anything

这篇关于为什么case类的每个新实例都会在Scala中再次评估懒惰的val?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆