gpt4 book ai didi

scala - 创建单一类型对象的列表

转载 作者:行者123 更新时间:2023-12-03 22:58:52 24 4
gpt4 key购买 nike

我有一个 Animal trait 和一些案例类如下

sealed trait Animal

trait Domestic extends Animal
trait Wild extends Animal

case class Dog(id: UUID = UUID.randomUUID()) extends Domestic
case class Lion(id: UUID = UUID.randomUUID()) extends Wild
这是我的 Herd 类,它可以包含单一类型动物的列表
case class Herd[T <: Animal](get: T*)
我想创造的是一群单一类型的动物。
val herd1 = Herd(Cat(), Cat())
val herd2 = Herd(Cat(), Lion())
在 Scala 中,两者都是有效的,但如果你看一下一群猫和狮子的含义,那就没有意义了。有没有办法限制 Herd成为单一类型?

最佳答案

尝试引入两个类型参数AB然后将它们与广义类型约束 A =:= B 关联起来

case class Herd[A <: Animal, B](x: A, y: B*)(implicit ev: A =:= B)

Herd(Lion()) // ok
Herd(Lion(), Lion()) // ok
Herd(Cat(), Lion()) // compile-time error

what exactly is =:=


考虑以下带有两个类型参数的方法 AB我们的目标是传达它们应该相等或至少 A应该是 B 的子类型
scala> def f[A, B](a: A, b: B): B = {
| val x: B = a
| x
| }
val x: B = a
^
On line 2: error: type mismatch;
found : a.type (with underlying type A)
required: B
上述定义中的两个类型参数是完全不相关的,方法体不能影响类型参数的类型推断,所以会出错。现在让我们尝试将它们与类型绑定(bind) A <: B 关联起来。
scala> def f[A <: B, B](a: A, b: B): B = {
| val x: B = a
| x
| }
def f[A <: B, B](a: A, b: B): B
所以这可以编译,但是编译器总是会尝试通过计算给定参数的最小上限来满足类型边界
scala> f(Lion(), Dog())
val res32: Product with Animal with java.io.Serializable = Lion(...)
我们需要更多的东西来解决编译器推导出最小上限的倾向,这就是广义类型等式约束发挥作用的地方
scala> def f[A <: B, B](a: A, b: B)(implicit ev: A =:= B): B = {
| val x: B = a
| x
| }
def f[A <: B, B](a: A, b: B)(implicit ev: A =:= B): B

scala> f(Lion(), Cat())
^
error: Cannot prove that Lion =:= Product with Animal with java.io.Serializable.
现在编译器仍然必须尝试生成给定参数的最小上限,但是它还必须满足能够生成见证 ev 的附加要求两种类型 AB平等。 (请注意,如果可能,编译器将自动实例化见证 ev。)
一旦我们有证人 ev我们可以在类型之间自由移动 AB通过其 apply方法,例如,考虑
scala> type A = Lion
type A

scala> type B = Lion
type B

scala> val a: A = Lion()
val a: A = Lion(...)

scala> val ev: =:=[A, B] = implicitly[A =:= B]
val ev: A =:= B = generalized constraint

scala> ev.apply(a)
val res44: B = Lion(...)
注意 ev.apply(a)类型到 B .我们可以申请的原因 =:=这种方式是因为它实际上是一个函数
scala> implicitly[(A =:= B) <:< Function1[A, B]]
val res43: A =:= B <:< A => B = generalized constraint
所以隐式参数列表
(implicit ev: A =:= B)
实际上是指定一个隐式转换函数
(implicit ev: A => B)
所以现在编译器能够在任何需要的地方自动注入(inject)隐式转换,所以以下
def f[A <: B, B](a: A, b: B)(implicit ev: A =:= B): B = {
val x: B = a
x
}
自动展开为
def f[A <: B, B](a: A, b: B)(implicit ev: A =:= B): B = {
val x: B = ev.apply(a)
x
}
总之,就像类型边界一样,通用类型约束是要求编译器在编译时对我们的代码库进行进一步检查的另一种方式。

关于scala - 创建单一类型对象的列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67773938/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com