2012-09-13 89 views
0

我有以下代码:斯卡拉 - 相同,但不同类型

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覆盖下一个变量 细胞[Cell.this.NEXT];可变未来有 不兼容的类型

这显然this将有类型VAL <: AnyVal这是一样的NEXT <: AnyVal,但是,我仍然得到错误。我怎么能告诉斯卡拉说next应该能够返回Cell[A <: AnyVal]类型的东西,但这种类型应该需要一样的类类型参数[VAL <: AnyVal] ???否则,我可以只使用[VAL]但它会过于严格,例如用于Cell[Int]这将限制next方法只返回Cell[Int]类型实例。但我想next要重新分配到其他任何Cell[*]类型的实例。

+1

“var next:Cell [NEXT]” - 我认为是错字,可能是“var next:CellT [NEXT]” –

+0

不,这不是一种类型 - 这就是我写代码的方式。但是你所说的是一个更合适的设计,所以我会解决它,谢谢! – noncom

回答

2

如果要next是重新分配给任何其他细胞[*]类型的实例,可以使用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,这一点)
细胞(1 ,此)
细胞(1,小区(假的,这一点))
细胞(假的,这一点)
细胞(1,细胞(真,此))
细胞(真实的,这一点)

+0

就是这样,谢尔盖!我将进一步研究这种方法,看看我能得到什么!谢谢! – noncom

1

这是显而易见的,这将有类型VAL <:AnyVal这是一样的NEXT <:AnyVal

不,他们是不一样的,他们只是有相同的约束。 NEXT尚未指定。试想一下,你以后子细胞是这样的:

class StringNextCell extends Cell { 
    type NEXT = String 
} 

现在,StringNextCell.next应该是Cell[String]类型,但由细胞的声明声明它作为Cell[Int]

+0

是的 - 是的,我的意思是,这就是代码的问题,我无法像你那样解释问题)。约束是一样的,但实际上可能存在这种类型的分歧指出。 – noncom

1

这不正是一个答案竟有如此警告。我在一个月前编写了非常类似的代码,并且我花了很多次迭代才知道,当谈到Scala打字时,粗糙更好。

请记住,Scala的类型参数检查只编译时间,所以它比你想象的频繁粗糙。花费15分钟让你的代码编译真的很烦人,只是发现你的X [Foo <:Bar]被视为X [_]。

我建议你先从:

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

且仅当你有一个迫切需要得到更具体。有可能,如果你需要知道下一个类型,你将需要做一个明确的运行时检查。

+0

他可能不得不做一个运行时检查(即模式匹配),但至少在约束条件下他会知道它是安全的。 –

+0

@AaronNovstrup和David:哈哈,你是对的!通常,在与Scala的类型系统对抗半小时后,我发现用'_'代替所有“复杂”类型的东西就可以完成这项工作:D。事实证明,在这种情况下,它也是解决方案的重要组成部分之一。是的,我还需要在类型上进行模式匹配,我们会看到,它将如何工作。也许我会在那里遇到更多的问题。 – noncom