斯卡拉案例类禁止按名称参数? [英] Scala case class prohibits call-by-name parameters?
问题描述
抽象类MyList [+ T]
case对象MyNil extends MyList [Nothing]
case class MyNode [T](h:T,t:=> MyList [T])扩展MyList [T]
//错误:`val'参数可能不是名称
问题在于呼叫方
我听说这是因为 val
或 var
构造函数参数不允许用于名称调用
。例如:
class A(val x:=> Int)
//错误:`val'参数可能不是名称
但是矛盾的是,正常的构造函数参数仍然是 val
,尽管 private
。例如:
class A(x:=> Int)
//传递
code>
所以问题:
val
还是 var
?
val
或 var
计算(或初始化)被延期?
不存在任何矛盾: class A(x:=> Int)
class A(private [this] val x:=> Int)
而不是 class A(private val x:=> INT)
。 private [this]
标记一个值instance-private,而没有进一步规范的private-modifier允许从该类的任何实例访问值。 不幸的是,定义一个的case类A(private [this] val x:=> Int)
不是允许。我认为这是因为case-classes需要访问其他实例的构造函数值,因为它们实现了 equals
方法。
然而,您可以实现案例类可以手动提供的功能:
abstract class MyList [+ T]
class MyNode [T](val h:T,t:=> MyList [T])扩展MyList [T] {
def getT = t //我们需要能够访问t
/ *编辑:实际上,这也会导致无限递归
重写def equals(other:任何):Boolean = other match {
case MyNode(i,y)if(getT == y)&& (h == i)=> true
case _ => false
} * /
覆盖def hashCode = h.hashCode
覆盖def toString =MyNode [+ h +]
}
object MyNode {
def apply [T](h:T,t:=> MyList [T])= new MyNode(h,t)
def unapply [T](n:MyNode [T])= Some(nh - > n.getT)
}
要检查这段代码,你可以试试:
def main(args:Array [String ]):Unit = {
lazy val first:MyNode [String] = MyNode(hello,second)
lazy val second:MyNode [String] = MyNode(world,first)
println(first)
println(second)
first match {
case MyNode(hello,s)=> println(第二个节点是+ s)
案例_ => println(false)
}
}
不幸的是,我没有肯定知道为什么禁止使用名为val和var的成员。但是,至少有一个危险:考虑case-classes如何实现 toString
;调用每个构造函数值的 toString
- 方法。这可以(并且在这个例子中)导致价值无限地自我调节。您可以通过将 t.toString
添加到 MyNode
的 toString
- 方法。
编辑:在阅读Chris Martin的评论之后: equals
的实现也将构成这个问题可能比执行 toString
(它主要用于调试)和 hashCode
(其中只会导致更高的冲突率,如果你不能把这个参数考虑在内)。你必须仔细考虑如何实现等于
是有意义的。
I want to implement an infinite list:
abstract class MyList[+T]
case object MyNil extends MyList[Nothing]
case class MyNode[T](h:T,t: => MyList[T]) extends MyList[T]
//error: `val' parameters may not be call-by-name
the problem is the call-by-name
is not allowed.
I've heard that it is because val
or var
constructor parameter is not allowed for call-by-name
. For example:
class A(val x: =>Int)
//error: `val' parameters may not be call-by-name
But the contradiction is that the normal constructor parameter is still val
, despite private
. For example:
class A(x: =>Int)
// pass
So the question :
- Is the problem really about
val
orvar
?- If that. Since the point for call-by-name is to defer computation, Why could not
val
orvar
computation(or initialization) be deferred?
- If that. Since the point for call-by-name is to defer computation, Why could not
- How to get around the cass class to implement an infinite list?
There is no contradiction: class A(x: => Int)
is equivalent to class A(private[this] val x: => Int)
and not class A(private val x: => Int)
. private[this]
marks a value instance-private, while a private-modifier without further specification allows accessing the value from any instance of that class.
Unfortunately, defining a case class A(private[this] val x: => Int)
is not allowed either. I assume it is because case-classes need access to the constructor values of other instances, because they implement the equals
method.
Nevertheless, you could implement the features that a case class would provide manually:
abstract class MyList[+T]
class MyNode[T](val h: T, t: => MyList[T]) extends MyList[T]{
def getT = t // we need to be able to access t
/* EDIT: Actually, this will also lead to an infinite recursion
override def equals(other: Any): Boolean = other match{
case MyNode(i, y) if (getT == y) && (h == i) => true
case _ => false
}*/
override def hashCode = h.hashCode
override def toString = "MyNode[" + h + "]"
}
object MyNode {
def apply[T](h: T, t: => MyList[T]) = new MyNode(h, t)
def unapply[T](n: MyNode[T]) = Some(n.h -> n.getT)
}
To check this code, you could try:
def main(args: Array[String]): Unit = {
lazy val first: MyNode[String] = MyNode("hello", second)
lazy val second: MyNode[String] = MyNode("world", first)
println(first)
println(second)
first match {
case MyNode("hello", s) => println("the second node is " + s)
case _ => println("false")
}
}
Unfortunately, I do not know for sure why call-by-name val and var members are prohibited. However, there is at least one danger to it: Think about how case-classes implement toString
; The toString
-method of every constructor value is called. This could (and in this example would) lead to the values calling themselves infinitely. You can check this by adding t.toString
to MyNode
's toString
-method.
Edit: After reading Chris Martin's comment: The implementation of equals
will also pose a problem that is probably more severe than the implementation of toString
(which is mostly used for debugging) and hashCode
(which will only lead to higher collision rates if you can't take the parameter into account). You have to think carefully about how you would implement equals
to be meaningfull.
这篇关于斯卡拉案例类禁止按名称参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!