我想有一个特征,有两种方法如下:
trait Foo[A] {
def bar1(): A
def bar2(a: A): Unit
}
现在的问题是,我不希望 A 传播。说:
val foos: List[Foo[???]] = ...
foos.foreach({ foo =>
val x = foo.bar1()
// stuff
foo.bar2(x)
})
在此代码中,类型 A 并不重要,但我无法让编译器相处融洽。
x的类型是动态的,这是我可能需要消除的东西吗?
有没有重写这种代码的模式?
Let
val foos: List[Foo[_]] = ???
这与
val foos: List[Foo[T] forSome { type T }] = ???
这使foos
成为对的列表。每对由一个类型T
和一个类型Foo[T]
的值组成。在foreach
中,解构该对以获取对该类型的访问权限并命名它,并获取值:
foos.foreach { case foo: Foo[t] =>
val x = foo.bar1() // inferred type t
foo.bar2(x) // foo.bar2 wants a t, x is a t, this is well-formed
}
斯卡斯蒂
注意:"对"在类型擦除后消失。在擦除的代码中,List
仅包含Foo
对象。有必要用case
显式解构该对。如果你不这样做,那么foo
将引用整个对,并且在每次使用时,编译器将隐式解构它。发生这种情况时,所包含类型的两个外观不被视为相等。
foos.foreach { foo =>
val x = foo.bar1()
foo.bar2(x)
}
与
foos.foreach { foo =>
val x = foo match { case foo0: Foo[t] => foo0.bar1() }
foo match { case foo0: Foo[u] => foo0.bar2(x) }
}
编译器看不到t
和u
实际上是相同的。这是因为定义x
时t
不在范围内,因此您最终会得到x: Any
,因此您丢失了类型信息。
尽管存在类型,这将在未来的 Scala 中工作(使用_
语法(。
你的意思是没关系?这很重要,而且很重要!
看看这个:
val x = foo.bar1()
// stuff
foo.bar2(x)
在这里,您需要确保x
的类型与foo.bar2
需要的类型相同。
您可能可以执行以下操作:
def process[A](data: List[Foo[A]]): Unit =
list.foreach { foo =>
val x = foo.bar1()
// stuff
foo.bar2(x)
}
但也许,你想用"动态">说的是你想要一个不同类型的Foo
列表。因此,哪一个并不重要,因为您知道每个 foo 都会生成一个它可以使用的值,如果是这样,您可以使用类型成员而不是类型参数:
trait Foo {
type A
def bar1(): A
def bar2(a: A): Unit
}
def process(data: List[Foo]): Unit =
list.foreach { foo =>
val x = foo.bar1()
// stuff
foo.bar2(x)
}