return 存在类型有意义吗?
Does it make sense to return an existential type?
如果我定义一个 return 存在类型的方法:
trait X[T] {
def hello(x: T):Unit = println(x)
}
def myX: X[_] = new X[Any] {}
如果我调用 myX
,我将得到一个类型为 X[_]
的值,但我无法向它传递任何内容:
val y: Any = 123
myX.hello(y) // compilation error!
我唯一能做的就是传递一个 Nothing
:
val y: Nothing = ???
myX.hello(y) // compilable, but useless
所以return存在类型的方法没有意义?
scala> trait X[T] {
| def hello(x: T):Unit = println(x)
| }
defined trait X
你定义的函数:
scala> def myX: X[_] = new X[Any] {}
myX: X[_]
scala> val xnothing = myX
xnothing: X[_] = $anon@5c44c582
scala> xnothing.hello(1)
<console>:14: error: type mismatch;
found : Int(1)
required: _
xnothing.hello(1)
^
"Fixed" 相同函数的定义 - 正确捕获类型 arg:
scala> def myY[T]: X[T] = new X[T] {}
myY: [T]=> X[T]
如果未传递通用 arg,则推断 Nothing
。
scala> val ynothing = myY
ynothing: X[Nothing] = $anon@53f0a4cb
您可以显式传递通用参数。
scala> val yint = myY[Int]
yint: X[Int] = $anon@555cf22
显然 Int
不是 Nothing
。
scala> ynothing.hello(1)
<console>:14: error: type mismatch;
found : Int(1)
required: Nothing
ynothing.hello(1)
^
这显然有效,因为我们明确地传递了 Int
:
scala> yint.hello(1)
1
现在这是一个有趣的部分。它之所以有效,是因为 Scala 可以计算出通用 arg 是 Int
(根据用法)。将其与上面的 ynothing
定义及其不编译的调用 ynothing.hello(1)
进行对比。
scala> myY.hello(1)
1
return this 存在类型没有多大意义,但它们在其他情况下可能很有用。作为一个简单的例子
// method which returns an existential type
// note that you can't return Array[Any] here,
// because arrays aren't covariant in Scala (which is a good thing)
def array: Array[_] = if (some condition) Array[Int](...) else Array[Double](...)
// all of following works
array(0)
array.length
// etc.
当然,如果你能写出一个方法的精确泛型类型,那你肯定更喜欢。
如果我定义一个 return 存在类型的方法:
trait X[T] {
def hello(x: T):Unit = println(x)
}
def myX: X[_] = new X[Any] {}
如果我调用 myX
,我将得到一个类型为 X[_]
的值,但我无法向它传递任何内容:
val y: Any = 123
myX.hello(y) // compilation error!
我唯一能做的就是传递一个 Nothing
:
val y: Nothing = ???
myX.hello(y) // compilable, but useless
所以return存在类型的方法没有意义?
scala> trait X[T] {
| def hello(x: T):Unit = println(x)
| }
defined trait X
你定义的函数:
scala> def myX: X[_] = new X[Any] {}
myX: X[_]
scala> val xnothing = myX
xnothing: X[_] = $anon@5c44c582
scala> xnothing.hello(1)
<console>:14: error: type mismatch;
found : Int(1)
required: _
xnothing.hello(1)
^
"Fixed" 相同函数的定义 - 正确捕获类型 arg:
scala> def myY[T]: X[T] = new X[T] {}
myY: [T]=> X[T]
如果未传递通用 arg,则推断 Nothing
。
scala> val ynothing = myY
ynothing: X[Nothing] = $anon@53f0a4cb
您可以显式传递通用参数。
scala> val yint = myY[Int]
yint: X[Int] = $anon@555cf22
显然 Int
不是 Nothing
。
scala> ynothing.hello(1)
<console>:14: error: type mismatch;
found : Int(1)
required: Nothing
ynothing.hello(1)
^
这显然有效,因为我们明确地传递了 Int
:
scala> yint.hello(1)
1
现在这是一个有趣的部分。它之所以有效,是因为 Scala 可以计算出通用 arg 是 Int
(根据用法)。将其与上面的 ynothing
定义及其不编译的调用 ynothing.hello(1)
进行对比。
scala> myY.hello(1)
1
return this 存在类型没有多大意义,但它们在其他情况下可能很有用。作为一个简单的例子
// method which returns an existential type
// note that you can't return Array[Any] here,
// because arrays aren't covariant in Scala (which is a good thing)
def array: Array[_] = if (some condition) Array[Int](...) else Array[Double](...)
// all of following works
array(0)
array.length
// etc.
当然,如果你能写出一个方法的精确泛型类型,那你肯定更喜欢。