Scala 3 从属类型
可以跑的源码在这里 👉 https://github.com/jcouyang/meow
Scala 2
如果经常使用 Shapeless, 你可能会熟悉一种叫 Aux 的 Pattern 这个pattern经常用来推倒输出类型
比如:
trait Second[L <: HList] {
type Out
def apply(value: L): Out
}
object Second {
type Aux[L <: HList, O] = Second[L] { type Out = O }
def apply[L <: HList](implicit inst: Second[L]): Aux[L, inst.Out] =
inst
}
Second(1 :: "2" :: HNil)
输出:
"2"
可以看见这个 Second 是 dependent types, 也就是说他的类型取决于输入的类型, 比如现在换一个 HList,他的 输出就不是 String 了:
Second("1" :: 2 :: HNil)
// => 2
输入变成 Int 了。
Scala 3
在 Scala 3 我们不仅可以用dependent methods,还可以声明 dependent function https://dotty.epfl.ch/docs/reference/new-types/dependent-function-types.html 。 也就是上面那个例子,可以进一步的简化:
trait Second[L <: HList] {
type Out
def apply(value: L): Out
}
object Second {
def apply[L <: HList](value: L) = (inst: Second[L]) ?=> inst(value)
}
其中 ?=>
https://dotty.epfl.ch/docs/reference/contextual/context-bounds.html
里面的问号并不是我的typo,这是简写的 (using inst: Second[L]) => inst(value)
注意看前后的区别:
- def apply[L <: HList](implicit inst: Second[L]): Aux[L, inst.Out] =
inst
+ def apply[L <: HList](value: L) = (inst: Second[L]) ?=> inst(value)
以前需要标明method类型为dependent types Aux[L, inst.Out]
现在你看,我们可以把 Aux 和 Out 消除掉,因为你可以直接返回一个 dependent function
如果你给这个 dependent function 标类型的话:
def apply[L <: HList](value: L): (inst: Second[L]) ?=> inst.Out =
(inst: Second[L]) ?=> inst(value)
它就跟Scala 2 dependent method的时候很像了,但是我们还是不用 Aux 类型的帮助。
如果懒得拉源代码下来玩,可以在 scastie 上试试 https://scastie.scala-lang.org/fyxXSR3ASj6rSkkERnUK7g