为什么Scala语言要求你初始化实例变量而不是依赖于默认值?

25

在Scala语言中,使用实例变量之前需要进行初始化。但是,Scala不会为您的变量提供默认值。相反,您必须使用通配符下划线手动设置其值,该下划线就像一个默认值,如下所示。

var name:String = _

我知道,我知道... 我可以在类定义中定义一个构造函数,该构造函数以我们的实例变量作为参数,因此Scala不会强制初始化它,如下所示:

class Person(var name:String) 
然而,我需要在类的主体中声明它,因为我需要使用一个Java注解,其ElementType为FIELD或METHOD;也就是说,它只能应用于在类主体中声明的实例变量或方法。
问题:为什么Scala语言要求您在类的主体中声明实例变量 - 无论是默认值_还是任何您想要的 - 而不是依赖于默认值?

3
我猜马丁偏好这个 :-) 至少它很明确,而额外的2个字符(包括空格时为4个字符)并不是非常困难。Java(一种非常冗长的语言)让赋值可以省略,这似乎有点傻。而且,说“构造函数参数”(不知道真正该怎么称呼它们:-/)不强制初始化似乎是误导性的——在实例化对象时,它们肯定会被初始化。 - user166390
3个回答

19
如果你使用以下代码,则表明你声明了name应该是抽象的:
class A {
  var name: String
}

我想你已经知道了这一点。那么你的问题更多是一个语法上的问题。 答案是要与其他可能的抽象候选项保持一致。

假设你想做像这样的事情:

class A {
   var variable: String = _ // variable has some default value (probably null)
   val value: String = _ // value cannot have any default values, since it cannot be reassigned later.
   def method: String = _ // method could return some default value (probably null)
   type theType = _ // what should the default type be? (Any perhaps?)
}

最后三个例子甚至不能编译。现在假设你想做这样的事情:

class A {
   var variable: String
   val value: String
   def method: String
   type theType
}
依我之见,即使是对 Scala 知之甚少的人,也只会看到声明部分。因为除了声明之外,没有别的东西可以引起歧义。唯一可能存在的混淆是,如果你来自另一种语言,并暂时假设存在某些默认值。但只要看到第一个例子(带有默认值的那个)这种混淆就会消失。顺便说一下,你的类必须是抽象层次结构的一部分,才能允许声明抽象成员,所以即使你是新手,编译器也会给你一些额外的帮助。
希望我的回答解决了你的问题,祝你编写愉快。

6
您可以在构造函数参数中指定注释来应用它。此外,您可能需要使用元注释来限制应用您正在使用的注释的目标 - 请参见http://www.scala-lang.org/api/2.10.2-RC2/index.html#scala.annotation.meta.package 关于“依赖默认值”的问题有些不太清楚。使用下划线进行初始化相当于将变量的值分配为null。您还考虑了哪些其他默认值?

我知道下划线符号用于分配默认值。但是,我想知道为什么Scala不允许在类体中声明像var name:String(没有下划线赋值)这样的变量名。您指出了Scala的一个很好的特性(+1),这是我不知道的。然而,它不能满足我的需求,因为如果我在类定义中声明构造函数,则还需要一个无参构造函数来覆盖它。 - Arthur Ronald
5
需要进行此赋值的原因是,我认为编译器需要区分抽象变量(编译为一对抽象方法)和具体变量,后者还需要在类文件中生成字段。 - Kris Nuttycombe

4

Scala在类体中使用"var name: String"没有问题。你试过吗?尽管它不是你想要的意思,但它是一个抽象变量。

abstract class A {
  var name: String
}
// some possible uses for abstract vars
trait B { type T ; var name: T }
class B1 extends B { type T = Int ; var name: Int = 5 }
// hey, no storage
class B2 extends B { type T = String ; def name = "abc" ; def name_=(x: String) = () }

如果我只是声明 var name:String;,当编译成 .class 文件时,Scala 编译器会抱怨:变量 name 未定义。因此,我想知道,即使出于设计问题,为什么 Scala 不允许在类体中使用 var name:String 而不声明其初始值;无论是默认值还是其他任何值。 - Arthur Ronald
1
你可以重新阅读我的回答,似乎你忽略了它。你是在问为什么存在“抽象”吗?未实现的抽象成员意味着你无法实例化该类。这是有意设计的,就像在Java中一样。 - psp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接