我在scala中有这样的东西:
abstract class Point[Type](n: String){
val name = n
var value: Type = _
}
到目前为止一切顺利。问题出现在扩展Point的类中。
case class Input[Type](n:String) extends Point(n){
def setValue(va: Type) = value = va
}
在setValue
行,我遇到了这个问题:
[error] type mismatch;
[error] found : va.type (with underlying type Type)
[error] required: Nothing
[error] def setValue(va: Type) = value = va
我尝试使用null
和null.asInstanceOf[Type]
初始化,但结果是一样的。
如何初始化值,以便可以在setValue中使用?
答案 0 :(得分:7)
您应该使用通用类型Input
指定Point
实现Type
,因为现在,由于未指定,它被视为Nothing
(我猜是编译器无法从setValue
方法推断出它。所以你必须做以下事情:
case class Input[Type](n:String) extends Point[Type](n){
def setValue(va: Type) = value = va
}
更多信息
我回答了这个问题的编译错误(它在scala 2.9.0.1上编译)。此外,我将此案例类视为现有类型的实现,如“Int”。在抽象类中使用_当然是一个坏主意,但是它不是禁止的,但是_并不总是为空,它是默认值,例如:var x:Int = _
将赋值{{ 1}}到0
。
答案 1 :(得分:1)
尝试以下方法:
包inputabstraction
abstract class Point[T](n:String){
def value: T
val name = n
}
case class Input[T](n:String, value:T) extends Point[T](n)
object testTypedCaseClass{
def test(){
val foo = Input("foo", "bar")
println(foo)
}
}
一个简单的应用程序来检查它是否有效:
import inputabstraction._
object TestApp extends Application{
testTypedCaseClass.test()
}
<强>解释强>
您犯的第一个错误是case class Input[Type](n:String) extends Point(n){
。 Point是一个类型化的类,因此当您使用extends Point(n)
调用超类构造函数时,需要指定Point
的类型。这样做:extends Point[T](n)
,其中T是您计划使用的类型。
第二个错误是您要定义和声明值:T:var value: Type = _
。在此声明中,_
是一个值。它的值是Nothing
。 scala编译器推断出Point[T]
是Point[Nothing]
。因此,当您尝试将其设置为setValue
方法正文中的类型时,必须将其设置为Nothing
,这可能不是您想要的。如果您尝试将其设置为Nothing
以外的任何内容,则会从上面获得类型不匹配,因为由于您使用了Nothing
,因此值被输入为_
。
第三个错误是使用var
代替val
或def
。 val
和def
可以互换,这意味着子类型可以覆盖val
或def
,scala编译器会为您解决。最好的做法是在抽象类和特征中使用def
将val定义为函数,因为子类型构造函数的初始化顺序是一个非常困难的事情(编译器决定如何algorithm如何从其超类型构造一个类)。 TL#DR ===在超类型中使用def。案例类参数会自动生成val
个字段,由于您要扩展一个Point,因此会创建一个覆盖Point[T]
中def值字段的val值字段。
由于类型推断和Type
是抽象的事实,你可以放弃Scala中的所有T
|| Point
抽象,因此可以通过val扩展值。
这样做依赖注入的首选方法是cake pattern,但是这个例子我已经为你的用例提供了工作。