Ответ 1
Нет противоречия: class A(x: => Int)
эквивалентно class A(private[this] val x: => Int)
, а не class A(private val x: => Int)
. private[this]
обозначает значение instance-private, а private-модификатор без дополнительной спецификации позволяет получить доступ к значению из любого экземпляра этого класса.
К сожалению, определение a case class A(private[this] val x: => Int)
также не допускается. Я предполагаю, что это потому, что case-классы нуждаются в доступе к значениям конструктора других экземпляров, потому что они реализуют метод equals
.
Тем не менее вы можете реализовать функции, которые класс case предоставит вручную:
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)
}
Чтобы проверить этот код, вы можете попробовать:
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")
}
}
К сожалению, я не знаю точно, почему призывные имена val и var запрещены. Однако для этого существует хотя бы одна опасность: подумайте о том, как реализуются классы case toString
; Вызывается toString
-метод каждого значения конструктора. Это могло бы (и в этом примере) привести к значениям, называющим себя бесконечно. Вы можете проверить это, добавив t.toString
в MyNode
toString
-метод.
Изменить: После прочтения комментария Криса Мартина: реализация equals
также будет представлять проблему, которая, вероятно, более серьезная, чем реализация toString
(которая в основном используется для отладки) и hashCode
(что приведет только к более высокой скорости столкновений, если вы не можете принять этот параметр). Вы должны тщательно подумать о том, как реализовать equals
, чтобы иметь смысл.