在通配符上键入Boundary"Stickyness"

Bru*_*eth 5 scala

我在scala论坛上看到了这篇文章.

这是一个回顾:

我刚刚意识到Scala编译器似乎没有在通配符上"延续"类型边界:

scala> class Foo { def foo = 42 }
defined class Foo
scala> class Bar[A <: Foo](val a: A)
defined class Bar
scala> def bar(x: Bar[_]) = x.a.foo
:7: error: value foo is not a member of Any
Run Code Online (Sandbox Code Playgroud)

我希望方法栏的参数仍然是Foo的上限,即使它的确切类型参数在方法中不重要.这种行为有特定的原因吗?

然后讨论进入Spec解释争议:)

说明?

最后海报提出了这样的解释:

但是,如果编译器为Bar [_]执行此操作,出于一致性原因,它也必须为Bar [A]执行此操作.然而,后者会产生一些奇怪的后果.def bar [A](x:Bar [A],y:Bob [A])例如突然必须携带Bob的隐式类型绑定.如果鲍勃有自己的类型限制,那将是非常混乱的.

我不明白,因为

def bar[A](x: Bar[A])
Run Code Online (Sandbox Code Playgroud)

因为Bar类型参数是有界的,所以不会单独编译.

无论如何,我相信以下将是完全有道理的:

def bar(x: Bar[_], y : Bob[_])
Run Code Online (Sandbox Code Playgroud)

解决方法

作为一种解决方法,他们建议:

def bar(x: Bar[_ <: Foo]) = x.a.foo
Run Code Online (Sandbox Code Playgroud)

除了不干燥之外,它会让事情变得困难:

让我们考虑一棵树

abstract class Tree[T <: Tree[T]] { val subTree : List[T] }
Run Code Online (Sandbox Code Playgroud)

现在,您将如何定义递归遍历树的函数(显然在Tree类之外定义):

def size( tree : Tree[_] ) = tree.subTree.size + tree.subTree.map(size(_)).sum
Run Code Online (Sandbox Code Playgroud)

显然不会工作,因为subTree将变成List [Any],所以我们需要一个类型参数:

def size[T <: Tree[T]]( tree : T ) = ...
Run Code Online (Sandbox Code Playgroud)

甚至更丑陋:

class OwnATree( val myTree : Tree[_] ){}
Run Code Online (Sandbox Code Playgroud)

应该成为

class OwnATree[T <: Tree[T]]( val myTree : T ){}
Run Code Online (Sandbox Code Playgroud)

等等......

我相信某处出了点问题:)

Tra*_*own 5

完成你想要的东西用最简单的方式sizeOwnATree方法是使用一个存在的类型:

def size(tree: Tree[T] forSome { type T <: Tree[T] }): Int =
  tree.subTree.size + tree.subTree.map(size(_)).sum
Run Code Online (Sandbox Code Playgroud)

和:

class OwnATree(val myTree: Tree[T] forSome { type T <: Tree[T] })
Run Code Online (Sandbox Code Playgroud)

你的Tree[_]版本实际上也使用了存在类型 - 它们只是包含在一些语法糖中.换一种说法,

def size(tree: Tree[_]): Int = ...
Run Code Online (Sandbox Code Playgroud)

只是语法糖:

def size(tree: Tree[T] forSome { type T }): Int = ...
Run Code Online (Sandbox Code Playgroud)

你不能将你需要的约束添加到下划线版本,但你可以添加到desberared版本.

  • 请注意,也可以定义为一个_type alias_的任何地方,如果需要把它写数十次这可能是有用的:`型AnyTree =树[T] forSome {类型T <:树[T]}`然后` def size(树:AnyTree)......` (4认同)