Предположим, есть черта:Особенности различных видов пути-зависимых типов в Скале
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) someAlgo
и someAlgoObjObj
являются наиболее правильными функциями; 2), и нет смысла использовать общую функцию в этом примере вообще.
И я хотел бы уточнить некоторые различия между родовыми функциями выше. Пожалуйста, исправьте меня, если я сделаю ошибки.
Так как я понимаю тип T
соответствует статического типа x
(назовем его X
) или явного типа общего вызова (я имею в виду algo[Int]
, например). Вот почему T#InnerType
соответствует типу в объявлении типа X
. Но x.InnerType
также соответствует InnerType
от статический тип x
. Где разница?
Далее ... someAlgoObjType
компилирует, так что кажется, что x.InnerType
должен быть подтип из T#InnerType
. Тогда это нормально, что someAlgoTypeObj
не компилируется, так как мы не можем сделать утапливание неявно. Хотя мы можем переписать последний:
def someAlgoTypeObj[T <: OuterTrait](x: T)(y: T#InnerType): x.InnerType = {
pairPrintln(x, y)
y.asInstanceOf[x.InnerType]
}
UPD1: Я нашел одно различие между someAlgoObjObj
и someAlgoTypeType
, если их использовать с параметром явного типа. Если мы напишем некоторый класс, расширяющий OuterTrait
:
class OuterIntClass extends OuterTrait{
type InnerType = Int
}
val x: OuterIntClass = new OuterIntClass()
val y: Int = 5
Тогда:
someAlgoObjObj[OuterTrait](x)(y) // OK
и следующий звонок не работает:
someAlgoTypeType[OuterTrait](x)(y)
есть большой [Блогпост] (http://danielwestheide.com /blog/2013/02/13/the-neophytes-guide-to-scala-part-13-path-dependent-types.html) на PDT, вы обязательно должны это прочитать – 4lex1v
Спасибо, это интересно. Но у меня все еще есть проблема с 'T # InnerType' ... – juliet