Scala构造函数参数的可访问性
Scala构造函数参数的可访问性
需要明确确定Scala构造函数参数的范围
根据此链接(https://alvinalexander.com/scala/how-to-control-visibility-constructor-fields-scala-val-var-private#comment-13237),只要将构造函数参数标记为private,就不会创建getter和setter方法。但是,即使参数被标记为private,我提供的代码仍然可以正常工作。
我看过这个StackOverflow链接(https://stackoverflow.com/questions/14694712/do-scala-constructor-parameters-default-to-private-val?). 这个链接和上面的链接相矛盾。有人能解释一下吗?实际上,代码段可以在StackOverflow链接中找到。
class Foo(private val bar: Int) { def otherBar(f: Foo) { println(f.bar) // 访问另一个foo的bar } }
下面的代码可以正常运行:
val a = new Foo(1) a.otherBar(new Foo(3))
它会打印出3。
根据第一个链接,代码应该导致编译错误,因为该参数是private的。
问题出现的原因是:构造函数中的参数被声明为类的成员变量,导致在类的其他方法中无法访问该参数。
解决方法是:将构造函数中的参数声明为普通的函数参数,而不是类的成员变量。这样虽然构造函数内部的代码仍然可以访问该参数,但它不是类的成员变量,因此在构造函数外部是不可见的。
以下是整理后的
如果你想要一个只在类内部可见的构造函数参数,不要将其声明为类的成员变量,而是将其声明为普通的函数参数:
class Foo(bar: Int) { def otherBar(f: Foo) { println(f.bar) // 错误:value bar is not a member of Foo } }
构造函数中的所有代码仍然可以访问`bar`,但它不是`Foo`的成员变量,因此在构造函数外部是不可见的。
在Scala语言规范中,private修饰符允许在直接封闭模板及其伴生模块或伴生类中进行访问。为了只允许在实例内部进行访问,可以使用修饰符private[this]。以下代码:
class Foo(private[this] val bar: Int) { def otherBar(f: Foo) { println(f.bar) // access bar of another foo } }
会导致以下错误:
[error] .../src/main/scala/sandbox/Main.scala:9:17: value bar is not a member of sandbox.Foo [error] println(f.bar) // access bar of another foo [error] ^ [error] one error found
为什么private[this] val bar比仅使用bar更好?如果只使用bar,它只是一个构造函数参数,在类Foo中不会创建成员变量。原帖的作者问为什么可以从另一个实例访问一个private成员变量。
那么为什么拥有一个成员变量比不拥有更好?这与反射有关吗?创建一个不需要的成员的其他原因是什么?
如果不需要成员变量,就不要使用它。我同意这一点。但据我所理解,原始问题是关于Scala中私有成员可访问性规则的。
感谢Harald的回答!当我们在构造函数参数中说"private val bar: Int"(没有'this')时,将创建一个名为'bar'的私有字段,带有getter和setter方法。如果这样是正确的,那么我在问题中提供的链接需要进行更正。
是的,你链接问题的第一个答案并不完全正确。裸的构造函数参数不会创建一个private val字段,它只是一个在构造函数范围内有效的值,就像任何其他函数参数一样。