【问题标题】:Scala - same but different typeScala - 相同但不同的类型
【发布时间】:2012-09-13 16:22:48
【问题描述】:

我有以下代码:

trait CellT[VAL <: AnyVal] {
  var value: VAL
  type NEXT <: AnyVal
  var next: CellT[NEXT]
}

abstract class Cell[VAL <: AnyVal] extends CellT[VAL] {
  var next = this  // defaults to `this`. ERROR
}

// impl example:
class CellInt extends Cell[Int] {
  var value: Int = 0
}

错误表明

在类型的特征 CellT 中覆盖变量 next 单元格[Cell.this.NEXT];变量 next 有 不兼容的类型

这里很明显this 的类型VAL &lt;: AnyValNEXT &lt;: AnyVal 相同,但是我仍然得到错误。我如何告诉 Scala next 应该能够返回 Cell[A &lt;: AnyVal] 类型的任何东西,但是这种类型应该 必须与类类型参数 [VAL &lt;: AnyVal] 相同?否则我可以只使用[VAL],但它会限制太多,例如对于Cell[Int],它将限制next 方法只返回Cell[Int] 类型的实例。但我希望 next 可以重新分配给任何其他 Cell[*] 类型实例。

【问题讨论】:

  • "var next: Cell[NEXT]" - 我认为是错字,可能是 "var next: CellT[NEXT]"
  • 不,这不是一个类型——我的代码就是这样写的。不过你说的是更合适的设计,那我就修一下,谢谢!!!

标签: scala inheritance types


【解决方案1】:

如果您希望 next 可重新分配给任何其他 Cell[*] 类型实例,您可以使用 existential types

trait CellT[VAL <: AnyVal] {
  var value: VAL
  var next: CellT[_ <: AnyVal]
}

abstract class Cell[VAL <: AnyVal] extends CellT[VAL] {
  var next: CellT[_ <: AnyVal] = this // defaults to `this`
  override def toString = "Cell(%s,%s)".format(value, if(next == this) "this" else next.toString)
}

// impl example:
class CellInt extends Cell[Int] {
  var value: Int = 0
}

class CellBoolean extends Cell[Boolean] {
    var value = false
}

var c1 = new CellInt
var c2 = new CellBoolean

println(c1)
c1.value = 1
println(c1)
c1.next = c2
println(c1)

println(c2)
c2.value = true
println(c1)
println(c2)

输出:

单元格(0,this)
单元格(1,this)
细胞(1,细胞(假,这个))
单元格(假,这个)
细胞(1,细胞(真,这个))
单元格(真,这个)

【讨论】:

  • 就是这样,谢尔盖!我将进一步使用这种方法,看看我能做到什么!谢谢!
【解决方案2】:

很明显,这将具有类型 VAL <: anyval next> 相同

不,它们不一样,它们只是共享相同的约束。 NEXT 尚未指定。想象一下,您随后像这样子类化 Cell:

class StringNextCell extends Cell {
    type NEXT = String
}

现在,StringNextCell.next 应该是 Cell[String] 类型,但您来自 Cell 的声明将其声明为 Cell[Int]

【讨论】:

  • 是的,是的,我的意思是,这就是代码的问题,我无法像你那样解释问题)约束是相同的,但实际上可以正如你所指出的那样,是那种类型的分歧。
【解决方案3】:

这与其说是一个警告,不如说是一个答案。一个月前我写了非常相似的代码,我经过多次迭代才知道,当涉及到 Scala 类型时,越粗越好。

请记住,Scala 类型参数检查仅在编译时进行,因此它通常比您想象的要粗略。花 15 分钟编译你的代码,却发现你的 X[Foo <: bar x>

我建议你从以下开始:

abstract class Cell[VAL] {
    var value: VAL
    var next: Cell[_]
}

只有在您有迫切需要时才能更具体。很有可能,如果您需要知道 next 的类型,无论如何您都需要进行明确的运行时检查。

【讨论】:

  • 他可能需要进行运行时检查(即模式匹配),但至少有约束他会知道这是安全的。
  • @AaronNovstrup 和大卫:哈哈,你说得对!通常,在与 Scala 的类型系统斗争半小时后,我发现只需用 _ 替换所有“复杂”类型的东西就可以了:D。事实证明,在这种情况下,它也是解决方案的重要部分之一。是的,稍后我还必须对类型进行模式匹配,我们将看到它将如何工作。也许我会在那里面临更多的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-27
  • 2018-02-23
  • 2019-12-18
  • 2019-08-18
  • 2013-03-28
  • 1970-01-01
  • 2010-10-30
相关资源
最近更新 更多