Scala 类型系统。 "Deferred" 类型参数。为什么这有效?
Scala typesystem. "Deferred" type parameter. Why this works?
我一直在写一些代码,它引导我:
trait SplitStrategy[E] {
def apply(seq: Seq[E]): Seq[(Int, Seq[E])]
}
object SplitByConsecutiveElements {
def apply[E](consecutiveValue: Seq[E] => E): SplitByConsecutiveElements[E] = new SplitByConsecutiveElements(consecutiveValue)
def withConsecutiveValueAsTheHighestCount[E]: SplitByConsecutiveElements[E] = {
val consecutiveValue: Seq[E] => E = seq => {
seq.foldLeft(Map.empty[E, Int].withDefaultValue(0)) {
case (m, v) => m.updated(v, m(v) + 1)
}.maxBy(_._2)._1
}
SplitByConsecutiveElements(consecutiveValue)
}
def main(args: Array[String]): Unit = {
println(SplitByConsecutiveElements.withConsecutiveValueAsTheHighestCount.apply(Seq(1, 1, 2, 1, 2)))
}
}
class SplitByConsecutiveElements[E](val consecutiveValue: Seq[E] => E) extends SplitStrategy[E] {
override def apply(seq: Seq[E]): Seq[(Int, Seq[E])] = splitSequenceBySequenceOfElements(seq, consecutiveValue(seq))
private def splitSequenceBySequenceOfElements[E](seq: Seq[E], consecutiveValue: E): Seq[(Int, Seq[E])] = {
// This is just a dummy operation, not the real algorithm
Seq((0, seq.filter(consecutiveValue == _)))
}
}
如果您查看 "main" 方法,您会看到我调用了 SplitByConsecutiveElements.withConsecutiveValueAsTheHighestCount
,然后将其应用于 Int
的序列。起初,我以为它不会编译。但它确实可以编译并正常工作。
我让它不起作用的理由是,在调用 SplitByConsecutiveElements.withConsecutiveValueAsTheHighestCount
时,我正在创建一个未知类型参数 E
的 SplitByConsecutiveElements[E]
。然后我应用 SplitByConsecutiveElements[E].someMethod
,其中 E
是已知的,但我已经创建了 SplitByConsecutiveElements[E]
的实例,而不是 SplitByConsecutiveElements[Int]
的实例。为什么这行得通?它就像编译时的 class transofrms 本身?
我现在脑子里乱七八糟的,希望我把我的担心表达好。
它起作用的原因有两个:
1) JVM 上的泛型被删除,因此可以在不知道 E
的情况下创建 SplitStrategy[E]
的实例。所以不需要 "transform the class at compile time".
2) 即使我们在一个没有删除泛型类型的平台上(比如,C# 的 CLR),这段代码仍然可以工作。
编译器尝试根据上下文推断 E
in SplitStrategy[E]
以使整个表达式有效。在你的情况下,它成功地猜测 E
是 Int
.
我一直在写一些代码,它引导我:
trait SplitStrategy[E] {
def apply(seq: Seq[E]): Seq[(Int, Seq[E])]
}
object SplitByConsecutiveElements {
def apply[E](consecutiveValue: Seq[E] => E): SplitByConsecutiveElements[E] = new SplitByConsecutiveElements(consecutiveValue)
def withConsecutiveValueAsTheHighestCount[E]: SplitByConsecutiveElements[E] = {
val consecutiveValue: Seq[E] => E = seq => {
seq.foldLeft(Map.empty[E, Int].withDefaultValue(0)) {
case (m, v) => m.updated(v, m(v) + 1)
}.maxBy(_._2)._1
}
SplitByConsecutiveElements(consecutiveValue)
}
def main(args: Array[String]): Unit = {
println(SplitByConsecutiveElements.withConsecutiveValueAsTheHighestCount.apply(Seq(1, 1, 2, 1, 2)))
}
}
class SplitByConsecutiveElements[E](val consecutiveValue: Seq[E] => E) extends SplitStrategy[E] {
override def apply(seq: Seq[E]): Seq[(Int, Seq[E])] = splitSequenceBySequenceOfElements(seq, consecutiveValue(seq))
private def splitSequenceBySequenceOfElements[E](seq: Seq[E], consecutiveValue: E): Seq[(Int, Seq[E])] = {
// This is just a dummy operation, not the real algorithm
Seq((0, seq.filter(consecutiveValue == _)))
}
}
如果您查看 "main" 方法,您会看到我调用了 SplitByConsecutiveElements.withConsecutiveValueAsTheHighestCount
,然后将其应用于 Int
的序列。起初,我以为它不会编译。但它确实可以编译并正常工作。
我让它不起作用的理由是,在调用 SplitByConsecutiveElements.withConsecutiveValueAsTheHighestCount
时,我正在创建一个未知类型参数 E
的 SplitByConsecutiveElements[E]
。然后我应用 SplitByConsecutiveElements[E].someMethod
,其中 E
是已知的,但我已经创建了 SplitByConsecutiveElements[E]
的实例,而不是 SplitByConsecutiveElements[Int]
的实例。为什么这行得通?它就像编译时的 class transofrms 本身?
我现在脑子里乱七八糟的,希望我把我的担心表达好。
它起作用的原因有两个:
1) JVM 上的泛型被删除,因此可以在不知道 E
的情况下创建 SplitStrategy[E]
的实例。所以不需要 "transform the class at compile time".
2) 即使我们在一个没有删除泛型类型的平台上(比如,C# 的 CLR),这段代码仍然可以工作。
编译器尝试根据上下文推断 E
in SplitStrategy[E]
以使整个表达式有效。在你的情况下,它成功地猜测 E
是 Int
.