scala中不同类型的路径依赖类型的特征

时间:2013-06-23 15:28:34

标签: scala path-dependent-type

假设有一个特征:

trait OuterTrait {
  type InnerType
}

现在我们可以编写非泛型函数someAlgo

def pairToString[S, U](x: S, y: U): String = 
  "{" + y.toString + " in " + x.toString + "}"

def pairPrintln[S, U](x: S, y: U) {
  println(pairToString(x, y))
}

def someAlgo(x: OuterTrait)(y: x.InnerType): x.InnerType = {
  pairPrintln(x, y)
  y
}

和一系列通用函数:

def someAlgoObjObj[T <: OuterTrait](x: T)(y: x.InnerType): x.InnerType = {
  pairPrintln(x, y)
  y
}

def someAlgoObjType[T <: OuterTrait](x: T)(y: x.InnerType): T#InnerType = {
  pairPrintln(x, y)
  y
}

def someAlgoTypeType[T <: OuterTrait](x: T)(y: T#InnerType): T#InnerType = {
  pairPrintln(x, y)
  y
}

还有一个通用函数无法编译:

def someAlgoTypeObj[T <: OuterTrait](x: T)(y: T#InnerType): x.InnerType = {
  pairPrintln(x, y)
  y
}

似乎: 1)someAlgosomeAlgoObjObj是最正确的功能; 2)在这个例子中根本没有使用泛型函数的意义。

我想澄清一下上述通用功能之间的一些区别。请纠正我,如果我犯了错误。

据我所知,类型T对应于{em>静态类型的x(称之为X)或显式类型的通用调用(我的意思是{{例如1}}。这就是为什么algo[Int]对应于T#InnerType类型声明中的类型的原因。但X也对应x.InnerType静态类型的InnerType。区别在哪里?

此外...... x会进行编译,因此someAlgoObjType似乎必须是x.InnerType子类型。那么T#InnerType无法编译就可以了,因为我们不能隐式地进行向下转换。虽然我们可以重写最后一个:

someAlgoTypeObj

UPD1:如果将def someAlgoTypeObj[T <: OuterTrait](x: T)(y: T#InnerType): x.InnerType = { pairPrintln(x, y) y.asInstanceOf[x.InnerType] } someAlgoObjObj与明确的类型参数一起使用,我发现它们之间存在差异。如果我们写一些扩展someAlgoTypeType的类:

OuterTrait

然后:

class OuterIntClass extends OuterTrait{
  type InnerType = Int
}
val x: OuterIntClass = new OuterIntClass()
val y: Int = 5

并且下次通话无效:

someAlgoObjObj[OuterTrait](x)(y) // OK

2 个答案:

答案 0 :(得分:0)

T#InnerType表示“某些 T中属于的InnerType”,而x.InnerType表示“给定 x中的属性的内部类型”(类型为OuterTrait) )”。

理解这些的关键在于给定x 中的某些T vs 中的。您可以将某些中的解释为某些T但我们没有哪个T实例,这意味着在两个Ts中不一定相同,所以,T#InnerType可以不能被证明等于另一个T#InnerType。

让我们分析一下签名:

/* 1 */ def someAlgoObjObj[T <: OuterTrait](x: T)(y: x.InnerType): x.InnerType = ???
/* 2 */ def someAlgoObjType[T <: OuterTrait](x: T)(y: x.InnerType): T#InnerType = ???
/* 3 */ def someAlgoTypeType[T <: OuterTrait](x: T)(y: T#InnerType): T#InnerType = ???
  1. 鉴于属于的x和InnerType,此x 将返回其InnerType。
  2. 鉴于属于的x和InnerType,此x 返回属于某些T 的InnerType,这意味着某些T 不一定是同一个实例X
  3. 鉴于属于某些T 的x和InnerType返回属于某些T 的InnerType
  4. 现在是第四个:

    def someAlgoTypeObj[T <: OuterTrait](x: T)(y: T#InnerType): x.InnerType = y
    

    签名读取:给定x和属于某些T 的InnerType,返回属于 this x 的InnerType。但是在实现中,我们尝试返回y,它属于一个不一定与x相同的T,因此编译器会抱怨。

答案 1 :(得分:0)

关于更新的小记录。

someAlgoTypeType[OuterTrait](x)(y) 

Failes,因为您的方法签名告诉它期望其y参数符合类型T#InnerType而您的y.type是Int。要使其工作,您应该将其类型更改为以下内容:

class OuterIntClass extends OuterTrait{
  type InnerType = Int
}
val x: OuterIntClass = new OuterIntClass()
val y: x.InnerType = 5

现在y的类型符合类型投影T#InnerTypesomeAlgoTypeType[OuterTrait](x)(y)编译