【问题标题】:Scala mutator naming conventions and requirementsScala mutator 命名约定和要求
【发布时间】:2016-04-17 19:18:57
【问题描述】:

我在理解 Scala 中关于 mutators 的命名时遇到了一些麻烦。这是我无法理解的部分:

class Company {
  private val _name: String = _

  def name = _name

  def name_=(name: String) {
    _name = name
  }
}

所以我知道 _name 是私有字符串,第一个 def 名称是 getter/accessor 而第二个是 setter/mutator。从本质上讲,我了解代码的含义和作用,但我不确定个人偏好与代码标准/所需的执行方式是什么。所有的变异器都会有 _ 后缀吗?用下划线作为私有属性前缀是标准的还是个人偏好?

或者我可以将 mutator 定义如下?

def name=(name: String) {
    _name = name
}

同样,我是否将私有 val 前缀与下划线或我可以将其更改为:

def name=(name: String) {
   name = name
}

我从Scala Naming ConventionsDaniel Spewak's Accessors/Mutators得到了上面的代码

【问题讨论】:

  • 你尝试编译你的代码吗?
  • 提供的链接对约定非常清楚。但是如果谈到编译器的限制,Scala 编译器要求你将你的 setter 命名为{getterName}_=,这是唯一的要求(除了签名的其他部分)。你可以随意命名你的私有变量,甚至完全跳过它,让你的 getter 和 setter 可计算
  • 虽然链接清楚地说明了约定,但它们并不清楚要求。我认为 Archeg 写的是一个好的答案的基础。
  • 我不认为这是Hungarian notation - 名称中的任何内容都与类型无关(在链接的文章中确实如此表示,下划线是一种匈牙利前缀,但仍然...)。

标签: scala properties naming-conventions


【解决方案1】:

这些都是很好的问题。其中一些在您喜欢的 Scala 文档中的文章中有所介绍,特别是关于 Accessors/Mutators 的部分。

mutator 方法的命名

简而言之,name_= 形式不是特殊语法,而是规范强制执行的命名约定。

让我们看看当您声明一个普通的旧 var 时,scalac 在 JVM 字节码级别产生了什么。理解scalac 生成的字节码对于理解该语言的更高层次的工作方式绝不是必要的,但是许多学习 Scala 的人都有一些 Java 经验,尽管如此,他们对 JVM 中的可能性以及什么有一些直觉不是。我认为这是我们在 Scala 规范中做出的一些决定中最接近的为什么

这里有一个名为Var.scala的源文件:

trait Var {
  var name: String
}

我将源代码编译成一个类文件并使用javap反编译它:

$ scalac Var.scala 
$ javap Var.class 
Compiled from "Var.scala"
public interface Var {
  public abstract java.lang.String name();
  public abstract void name_$eq(java.lang.String);
}

正如我们所见,一个 trait 中的 var 声明了两个 JVM 方法,一个 getter 和一个 setter。 getter 采用var 的名称,而 setter 的名称有点奇怪。这里,$eq 就是 Scala 标识符中的 = 在它生成的类文件中由 scalac 编码的方式。这是 Scala 规范的一部分,是不同编译单元之间的二进制兼容性所必需的。

因此,从 Scala 中看到的 setter 名称只是 name_=。这也是 Scala 规范的一部分。当我们编写一个设置var 值的语句时,会生成对具有该表单名称的方法的调用。当我们编写一个只读取var 的语句时,会生成对第一个方法的调用。

我们可以直接声明这两个方法,而不是声明var

trait ValAndDef {
  val name: String
  def name_=(newName: String): Unit
}

编译和反编译 this 将显示与以前完全相同的方法。也没有什么可以阻止您仅声明其中一种方法,这将创建一个只能读取但不能写入的成员,反之亦然。

私有包装字段的命名

到目前为止,我只讨论了声明一个字段。 实现该字段还意味着将存储添加到var 或在直接声明时实现方法。在 class 而不是 trait 中声明 var 将自动添加一个字段来存储 var 的值:

class VarClass {
  var name: String = _
}

$ javap -private VarClass.class
Compiled from "VarClass.scala"
public class VarClass {
  private java.lang.String name;
  public java.lang.String name();
  public void name_$eq(java.lang.String);
  public VarClass();
}

如果您决定使用一对方法来实现该字段,则必须自己声明这样一个私有字段。 Scala 规范没有说明在这种情况下应该如何命名该字段(它是私有的,因此不属于任何互操作性问题的一部分)。

我唯一能找到的“官方”是我在顶部链接的文章中的一段,它提倡支持字段的_name命名模式,同时还声明:

虽然匈牙利表示法非常难看,但它确实具有消除 _name 变量歧义而不会使标识符混乱的优点。

因此,是否要遵循该指导取决于您。 ¯\_(ツ)_/¯

【讨论】:

    猜你喜欢
    • 2019-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-17
    相关资源
    最近更新 更多