普通类型的模式匹配

时间:2010-12-25 07:00:04

标签: scala

为什么我不能模式匹配Node [T]?

object Visitor {
  def inorder[T](root: Node[T]) : Unit = {
    root match {
    case End => return;
    case Node[T] => {
      if( root.left != null )
          inorder( root.left )

      println( root.toString );
      inorder( root.right );
    }
    case _ => return;
    }
  }
}

更新

代码是99 scala problems

的逐字副本

我收到了这个编译时错误:

BinaryTree.scala:25: '=>' expected but '[' found.
[error]         case Node[T] => {
[error]                  ^
[error] one error found

第25行指向

case Node[T] => {

4 个答案:

答案 0 :(得分:8)

在某些情况下,你可以绑定type参数。绑定这样的类型参数可以用于类型化模式匹配子句的主体 - 由于擦除,这些绑定被擦除,这意味着你无法在运行时区分它们(这种东西在.NET CLR中是可能的)。 p>

您的代码似乎没有使用该类型 - 需要查看Node,End的定义。实现所需内容的简单方法可能是忽略Node [T]的类型参数。下面是一个使用正确语法执行此操作的示例。

请注意,如果要编写与类型(通用或非通用)匹配的模式,则它始终具有v : T形式。另一方面,如果您匹配案例类,则模式具有形状C(p1...,pN)。语言规范包含所有细节。

我们还可以将它绑定到a,而不是将类型绑定到类型变量_,以强调我们不使用此类型。

trait Tree[+T]
abstract class Node[+T] extends Tree[T] {
   def left: Tree[T]
   def right: Tree[T]
}
object End extends Tree[Nothing]

object Visitor {
  def inorder[T](root: Tree[T]) : Unit = {
    root match {
      case End => return;
      case node:Node[a] => {
        inorder( node.left ) // node.left has the type Tree[a]
        println( node.toString );
        inorder( node.right );
      }
      case _ => return;
    }
  }
}

答案 1 :(得分:7)

好吧,我通过解释器运行你的代码,我认为它与类型擦除没有任何关系。可能只是一些语法错误。试试这个:

object Visitor {
  def inorder[T](root: Node[T]): Unit = {
    root match {
    case End => return;
    case n:Node[_] => {
      if( root.left != null )
          inorder( root.left )

      println( root.toString );
      inorder( root.right );
    }
    case _ => return;
    }
  }
}

您需要指明将绑定到匹配项的变量名称,例如n:Node[T]。这会给你一个关于类型擦除的警告,你可以使用n:Node[_]删除它。编译器可以根据root.left的类型推断出root.rightroot的类型,因此类型擦除在这里并没有真正发挥作用......

注意:我刚检查了规范,类型模式的语法是:

varid ':' TypePat
'_' ':' TypePat

如果您提供编译器的实际错误消息,以及Node和End的定义,那将会有所帮助,否则我们需要推断所有这些。


编辑:

假设您正在编译http://aperiodic.net/phil/scala/s-99/tree.scala,您的代码确实存在语法错误。使用n:Node[_]。然后你会得到一些类型错误。这对我有用:

import binarytree._
object Visitor {
  def inorder[T](root: Tree[T]) : Unit = {
    root match {
    case End => return;
    case n:Node[_] => {
      if( n.left != null )
          inorder( n.left )
      println( n.toString );
      inorder( n.right );
    }
    case _ => return;
    }
  }
}

答案 2 :(得分:2)

为了在运行时为Scala中的泛型匹配已知类型,您需要使用清单(q.v.)编写代码的方式,类型将被删除。

答案 3 :(得分:2)

此行为称为type erasure。使用Manifests,您可以制定解决方法。有关详细信息,请参阅this question