[英]Bind wildcard type argument in Scala
在 Scala 2 中,您當然可以使用通配符或存在類型作為類型 arguments。但是,這意味着您並不總是有想要使用的類型的名稱。 這有時會導致奇怪的情況,您需要依靠類型推斷來規避顯式編寫類型。
這是我的意思的一個有點人為的例子:
case class Container[T](value: T) {
def replace(value: T): Container[T] = Container(value)
}
def identity[T](container: Container[T]): Container[T] = {
// A weird way of writing the identity function,
// but notice that I have essentially given the name
// `T` to the `_`
container.replace(container.value)
}
var x: Container[_] = Container[Int](1)
// This works, but as far as I know, there's no way to explicitly
// pass the type for `T`. For example, something like identity[_](x) won't work.
identity(x)
// This also fails to work, but if we could assign a name to the `_`, like `T`,
// then it would become obvious that this should work.
// x.replace(x.value)
有沒有辦法更干凈地解決這個問題? 如果你能寫出類似這樣的東西,那就太好了:
let Container[T] = x.type in {
// Now there is a type T in this scope,
// and x has type `Container[T]`
}
據我所知,Scala 中不存在任何此類內容。是否有我缺少的功能。 另外,有沒有人知道其他語言的類似功能?
使用類型模式匹配(使用 2.13 測試):
case class Container[T](value: T) {
def replace(value: T): Container[T] = Container(value)
}
val x: Container[_] = Container[Int](1)
val y: Container[_] = x match {
case c => c.replace(c.value)
}
實際類型本身在代碼中沒有名稱,實際上是不可見的,但基本上是這樣的:
case class Container[T](value: T) {
def replace(value: T): Container[T] = Container(value)
}
val x: Container[_] = Container[Int](1)
val y: Container[_] = x match {
case c: Container[t] =>{
val v: t = c.value
c.replace(v)
}
}
類型模式t
綁定了存在量化類型,可以在后面的表達式中使用,這樣v: t
就可以打出來了, c.replace(v)
也可以打出來。
另請參閱以下相關問題:
另一種選擇是使T
成為類型成員而不是類型參數。 在這種情況下,存在類型僅對應於Container
而特定類型是Container { type T =... }
(又名Container.Aux[...]
)。 不幸的是,類型成員類型不能在 class 主構造函數中使用
case class Container(value: T) { // not found: type T
type T
//...
}
所以我用特征+工廠方法替換案例 class
trait Container {
type T
def value: T
def replace(value: T): Container.Aux[T] = Container(value)
}
object Container {
type Aux[_T] = Container { type T = _T }
// factory method
def apply[_T](_value: _T): Aux[_T] = new Container {
override type T = _T
override val value: T = _value
}
}
val x: Container = Container[Int](1)
x.replace(x.value) // compiles
def identity[T](container: Container.Aux[T]): Container.Aux[T] =
container.replace(container.value)
identity[x.T](x) // compiles
請注意,我將x
val
而不是var
,以便路徑相關類型xT
有意義。
也許您更喜歡保留 case class,因為編譯器為 case 類生成的所有語法糖。 在這種情況下,我們可以引入一個額外的特征
trait IContainer {
type T
def value: T
def replace(value: T): IContainer.Aux[T]
}
object IContainer {
type Aux[_T] = IContainer { type T = _T }
}
case class Container[_T](value: _T) extends IContainer {
override type T = _T
override def replace(value: T): Container[T] = Container(value)
}
val x: IContainer = Container[Int](1)
x.replace(x.value) // compiles
def identity[T](container: IContainer.Aux[T]): IContainer.Aux[T] =
container.replace(container.value)
identity[x.T](x) // compiles
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.