这件事不在 Scala 3 中。在 Scala 2.13.6 中,类似代码无法编译
import shapeless.the
import java.time.{LocalDateTime, LocalTime}
trait Circular[T] {
type Parent
}
implicit object localTimeCircular extends Circular[LocalTime] {
type Parent = LocalDateTime
}
// implicit val localTimeCircular: Circular[LocalTime] {type Parent = LocalDateTime} = new Circular[LocalTime] {
// type Parent = LocalDateTime
// }
final class CircularMap[K, +V]()(implicit val circular: Circular[K])
val summoned = the[Circular[LocalTime]]
val daily = new CircularMap[LocalTime, Int]()
println(summoned == daily.circular) // Prints true
implicitly[localTimeCircular.Parent =:= LocalDateTime]
implicitly[summoned.Parent =:= LocalDateTime]
//implicitly[daily.circular.Parent =:= LocalDateTime] // doesn't compile
https://scastie.scala-lang.org/DmytroMitin/lsX3fS3ET0ajzChwl2Mctw
(我将implicitly 替换为the 在一处,因为implicitly 会破坏类型细化,summon 更像the)。
让我们简化您的代码,以便弄清楚发生了什么。让我们移除隐含(让我们明确地解决它们)
import java.time.{LocalDateTime, LocalTime}
trait Circular[T] {
type Parent
}
val localTimeCircular = new Circular[LocalTime] {
type Parent = LocalDateTime
}
final class CircularMap[K, +V](val circular: Circular[K])
val summoned = localTimeCircular
val daily = new CircularMap[LocalTime, Int](localTimeCircular)
println(summoned == daily.circular) // Prints true
implicitly[localTimeCircular.Parent =:= LocalDateTime]
implicitly[summoned.Parent =:= LocalDateTime]
//implicitly[daily.circular.Parent =:= LocalDateTime] // doesn't compile
问题在于路径相关类型的设计使得即使x == x1 也不需要x.T =:= x1.T
In the latest release of scala (2.12.x), is the implementation of path-dependent type incomplete?
Force dependent types resolution for implicit calls
How to create an instances for typeclass with dependent type using shapeless
summoned == daily.circular 是真的,但 summoned 的类型为 Circular[LocalTime] { type Parent = LocalDateTime },而 daily.circular 的类型为 Circular[LocalTime]。您这样指定:val circular: Circular[K]。因此,您将精炼类型Circular[LocalTime] { type Parent = LocalDateTime }(我们将其表示为Circular.Aux[LocalTime, LocalDateTime])向上转换为其超类型,即没有精炼的类型Circular[LocalTime](又名存在类型Circular.Aux[LocalTime, _])。所以类型 localTimeCircular.Parent 和 summoned.Parent 是 LocalDateTime 但类型 daily.circular.Parent 是抽象的。例如,如果你想恢复类型细化,你可以定义
final class CircularMap[K, +V, P](val circular: Circular[K] {type Parent = P})
另一种方法是使用单例类型
final class CircularMap[K, +V](val circular: localTimeCircular.type)
有没有在不引入类型参数P的情况下不丢失细化Circular[LocalTime] { type Parent = LocalDateTime }的方法
班级CircularMap?就像是
final class CircularMap[K, +V](val circular: Circular[K] { type Parent = X }) 其中X 将在CircularMap 主体的范围内引入一个新的类型变量。
您想要的实际上是类上的多个类型参数列表(以便在class CircularMap[K, +V][P] 中您可以指定K、V 并推断P)
https://github.com/scala/bug/issues/4719
https://contributors.scala-lang.org/t/multiple-type-parameter-lists-in-dotty-si-4719/2399
你可以模仿他们
import java.time.{LocalDateTime, LocalTime}
trait Circular[T] {
type Parent
}
val localTimeCircular = new Circular[LocalTime] {
type Parent = LocalDateTime
}
trait CircularMap[K, +V] {
type P
val circular: Circular[K] {type Parent = P}
}
object CircularMap {
def apply[K, V]: PartiallyApplied[K, V] = new PartiallyApplied[K, V]
class PartiallyApplied[K, V] {
def apply[_P](_circular: Circular[K] {type Parent = _P}): CircularMap[K, V] {type P = _P} = new CircularMap[K, V] {
override type P = _P
override val circular: Circular[K] {type Parent = _P} = _circular
}
}
}
val summoned = localTimeCircular
val daily = CircularMap[LocalTime, Int](localTimeCircular)
println(summoned == daily.circular) // Prints true
implicitly[localTimeCircular.Parent =:= LocalDateTime]
implicitly[summoned.Parent =:= LocalDateTime]
implicitly[daily.circular.Parent =:= LocalDateTime] // compiles