1

我在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

我尝试过初始化,nullnull.asInstanceOf[Type]结果是一样的。

如何初始化值以便可以在 setValue 中使用?

4

2 回答 2

7

您应该使用泛型类型指定Input实现,因为现在,由于没有指定,它被认为是(我猜编译器无法从方法中推断出它)。因此,您必须执行以下操作:PointTypeNothingsetValue

case class Input[Type](n:String) extends Point[Type](n){
  def setValue(va: Type) = value = va
}

更多信息

我为编译错误回答了这个问题(它确实在 scala 2.9.0.1 上编译)。此外,我将此案例类视为现有类型的实现,例如“Int”。在抽象类中使用 _ 当然是一个坏主意,但是并不禁止,但是 _ 并不总是 null,它是默认值,例如:var x:Int = _将值分配0x.

于 2012-04-23T19:33:53.857 回答
1

尝试以下操作:

包输入抽象

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 是您计划使用的类型。

第二个错误是您在此处定义和声明 value:T: var value: Type = _。在这个语句中,_是一个值。它的值为NothingPoint[T]scala 编译器由此推断出Point[Nothing]. 因此,当您尝试将其设置为setValue方法主体中的类型时,您必须将其设置为Nothing,这可能不是您想要的。如果您尝试将其设置为除 之外的任何内容Nothing,您将从上面得到类型不匹配,因为Nothing由于您使用了_.

第三个错误是使用var代替valdefvalanddef可以互换覆盖,这意味着子类型可以用valor覆盖def,scala 编译器会为你解决这个问题。将 val 定义为def在抽象类和特征中使用的函数是最佳实践,因为子类型构造函数的初始化顺序很难正确处理(编译器如何决定如何从其超类型构造类有一个算法) . TL#DR === 在超类型中使用 def。案例类参数是自动生成的val字段,由于您正在扩展一个点,因此将创建一个 val 值字段,该字段将覆盖Point[T].

你可以摆脱这一切Type|| TScala 中的抽象是因为类型推断和抽象的事实Point,因此可以通过 val 扩展值。

像这样进行依赖注入的首选方法是cake pattern,但我提供的这个示例适用于您的用例。

于 2012-04-23T20:42:44.947 回答