gpt4 book ai didi

scala - 在特征中定义一个值而不是定义一个值有什么好处吗?

转载 作者:行者123 更新时间:2023-12-03 23:41:51 25 4
gpt4 key购买 nike

在 Scala 中,val可以覆盖 def , 但是一个 def无法覆盖 val .

那么,声明特征是否有优势,例如像这样:

trait Resource {
val id: String
}

而不是这个?
trait Resource {
def id: String
}

后续问题是:编译器如何对待 调用 val s 和 def s 在实践中有所不同,它实际上对 val 做了什么样的优化年代?编译器坚持 val s 是稳定的——在实践中对编译器意味着什么?假设子类实际上正在实现 idval .将其指定为 def 是否会受到惩罚?在特质?

如果我的代码本身不需要 id 的稳定性成员(member),总是使用 def 是否被认为是一种好习惯? s 在这些情况下并切换到 val s 仅当此处确定了性能瓶颈时——这可能是多么不可能?

最佳答案

简短回答:

据我所知,这些值总是通过访问器方法访问的。使用 def定义了一个简单的方法,它返回值。使用 val定义了 私有(private) [*] final 字段,带有访问器方法。所以在访问方面,两者的区别非常小。区别在于概念,def每次都会重新评估,val只评估一次。这显然会对性能产生影响。

[*] Java 私有(private)

长答案:

让我们看下面的例子:

trait ResourceDef {
def id: String = "5"
}

trait ResourceVal {
val id: String = "5"
}
ResourceDef & ResourceVal生成相同的代码,忽略初始化器:
public interface ResourceVal extends ScalaObject {
volatile void foo$ResourceVal$_setter_$id_$eq(String s);
String id();
}

public interface ResourceDef extends ScalaObject {
String id();
}

对于生成的子类(包含方法的实现), ResourceDef产生如你所料,注意该方法是静态的:
public abstract class ResourceDef$class {
public static String id(ResourceDef $this) {
return "5";
}

public static void $init$(ResourceDef resourcedef) {}
}

对于 val,我们只需调用包含类中的初始化程序
public abstract class ResourceVal$class {
public static void $init$(ResourceVal $this) {
$this.foo$ResourceVal$_setter_$id_$eq("5");
}
}

当我们开始扩展时:
class ResourceDefClass extends ResourceDef {
override def id: String = "6"
}

class ResourceValClass extends ResourceVal {
override val id: String = "6"
def foobar() = id
}

class ResourceNoneClass extends ResourceDef

在我们覆盖的地方,我们在类中获得了一个方法,它可以满足您的期望。 def 是简单的方法:
public class ResourceDefClass implements ResourceDef, ScalaObject {
public String id() {
return "6";
}
}

并且 val 定义了一个私有(private)字段和访问器方法:
public class ResourceValClass implements ResourceVal, ScalaObject {
public String id() {
return id;
}

private final String id = "6";

public String foobar() {
return id();
}
}

请注意,即使 foobar()不使用字段 id ,但使用访问器方法。

最后,如果我们不重写,那么我们会得到一个调用 trait 辅助类中的静态方法的方法:
public class ResourceNoneClass implements ResourceDef, ScalaObject {
public volatile String id() {
return ResourceDef$class.id(this);
}
}

我已经删除了这些示例中的构造函数。

因此,总是使用访问器方法。我认为这是为了避免在扩展可以实现相同方法的多个特征时出现并发症。它很快变得复杂起来。

更长的答案:

Josh Suereth 在 Binary Resilience at Scala Days 2012 上做了一个非常有趣的演讲,它涵盖了这个问题的背景。对此的摘要是:

This talk focuses on binary compatibility on the JVM and what it means to be binary compatible. An outline of the machinations of binary incompatibility in Scala are described in depth, followed by a set of rules and guidelines that will help developers ensure their own library releases are both binary compatible and binary resilient.

In particular, this talk looks at:

  • Traits and binary compatibility
  • Java Serialization and anonymous classes
  • The hidden creations of lazy vals
  • Developing code that is binary resilient

关于scala - 在特征中定义一个值而不是定义一个值有什么好处吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13126104/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com