简体   繁体   English

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

[英]Features of different kinds of path-dependent types in scala

Suppose there is a trait: 假设有一个特征:

trait OuterTrait {
  type InnerType
}

Now we can write non-generic function someAlgo : 现在我们可以写一些非泛型函数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
}

and series of generic functions: 和一系列通用功能:

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
}

And one more generic function doesn't compile: 而另一个通用函数不编译:

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

It seems that: 1) someAlgo and someAlgoObjObj are the most correct functions; 看来:1) someAlgosomeAlgoObjObj是最正确的功能; 2) and there is no sense to use generic function in this example at all. 2)在这个例子中根本没有使用泛型函数的意义。

And I would like to clarify some differences between generic functions above. 我想澄清上面的通用函数之间的一些差异。 Please, correct me, If I make errors. 请纠正我,如果我犯了错误。

So as I understand type T corresponds to static type of x (call it X ) or explicit type of generic call (I mean algo[Int] for instance). 因此,据我所知,类型T对应于静态类型的x (称为X )或显式类型的通用调用(我的意思是algo[Int] )。 That's why T#InnerType corresponds to type in declaration of type X . 这就是T#InnerType对应于X类型声明中的类型的原因。 But x.InnerType also corresponds to InnerType of static type of x . x.InnerType也相当于InnerType 静态类型的x Where is the difference? 区别在哪里?

Further... someAlgoObjType compiles, so it seems that x.InnerType must be subtype of T#InnerType . 进一步... someAlgoObjType编译,因此似乎x.InnerType必须是T#InnerType 子类型 Then it is OK that someAlgoTypeObj doesn't compile, since we can't make downcast implicitly. 然后, someAlgoTypeObj无法编译,因为我们无法隐式地进行向下转换。 Though we can rewrite last one: 虽然我们可以改写最后一个:

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

UPD1: I found one difference between someAlgoObjObj and someAlgoTypeType if use them with explicit type parameter. UPD1:我发现someAlgoObjObjsomeAlgoTypeType之间存在一个区别,如果将它们与显式类型参数一起使用。 If we write some class extending OuterTrait : 如果我们编写一些扩展OuterTrait类:

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

Then: 然后:

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

and next call doesn't work: 和下一个电话不起作用:

someAlgoTypeType[OuterTrait](x)(y)

T#InnerType means "A InnerType belonging in some T" while x.InnerType means "A InnerType belonging in a given x (of type OuterTrait)". T#InnerType表示“属于某些 T的内部类型”,而x.InnerType表示“属于给定 x(类型为OuterTrait)的内部类型”。

The key here in understanding these is in some T vs in a given x . 理解这些的关键在于给定x 中的一些T vs。 You can interpret in some as some T but we don't which T instance , meaning that in a two Ts aren't necessarily the same, so, T#InnerType can't be proven to be equal to another T#InnerType. 你可以将某些解释为某些T但我们没有哪个T实例 ,这意味着在两个Ts中不一定相同,因此,T#InnerType不能被证明等于另一个T#InnerType。

Let's analyze the signatures: 我们来分析一下签名:

/* 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. Given x and InnerType belonging in this x returns the its InnerType. 给定x和属于此x的InnerType返回其InnerType。
  2. Given x and InnerType belonging in this x returns InnerType belonging to some T , meaning a some T is not necessarily the same instance as x. 给定x和属于此x的 InnerType返回属于某个T的 InnerType,意味着某个T不一定是与x相同的实例。
  3. Given x and InnerType belonging to some T returns InnerType belonging to some T 给定属于某些T的 x和InnerType返回属于某些T的 InnerType

Now for the forth one: 现在为第四个:

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

The signature reads: given x and InnerType belonging to some T , returns the InnerType belonging to this x . 签名读取:给定属于某些T的 x和InnerType,返回属于此x的InnerType。 But in the implementation, we try to return y, which belongs to a T that's not necessarily the same as x, hence the compiler complains. 但是在实现中,我们尝试返回y,它属于一个不一定与x相同的T,因此编译器会抱怨。

Little note about update . 关于更新的小注释。

someAlgoTypeType[OuterTrait](x)(y) 

Failes because your method signature tells that it expects its y parameter to conform to the type T#InnerType and your y.type is Int. Failes,因为你的方法签名告诉它期望它的y参数符合T#InnerType类型,你的y.type是Int。 To make it work you should change it's type to the following: 要使其工作,您应该将其类型更改为以下内容:

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

Now y 's type satisfies type projection T#InnerType and someAlgoTypeType[OuterTrait](x)(y) compiles 现在y的类型满足类型投影T#InnerTypesomeAlgoTypeType[OuterTrait](x)(y)编译

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM