泛型类型的模式匹配

发布于 2024-10-09 02:32:32 字数 723 浏览 0 评论 0原文

为什么我不能与 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问题

我收到此编译时错误:

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

第 25 行指向该行

case Node[T] => {

Why can't I pattern match against 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;
    }
  }
}

UPDATE:

The code is a verbatim copy from 99 scala problems

I'm getting this compile-time error:

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

Line 25 points to the line

case Node[T] => {

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

放手` 2024-10-16 02:32:32

在某些情况下,您可以绑定类型参数。绑定此类类型参数可用于对模式匹配子句的主体进行类型检查——由于擦除,这些绑定会被擦除,这意味着您无法在运行时区分它们(此类内容在 .NET CLR 中是可能的)。

不过,您的代码似乎没有使用该类型 - 人们需要查看 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;
    }
  }
}

You can bind the type parameter in some circumstances. Binding such type parameters can be used for typechecking the body of the pattern matching clause -- due to erasure, these bindings get erased and that means you cannot distinguish between them at runtime (such stuff is possible in the .NET CLR).

Your code does not seem to make use of the type though - one would need to see the definitions of Node, End. The simple way to achieve what you want is probably to just ignore what the type argument of Node[T] is. Below is an example that does this, with the correct syntax.

Note that if you want to write a pattern that matches on a type (generic or not), it always has the form v : T. If on the other hand, you match on case classes, then the pattern has the shapes C(p1...,pN). The language spec has all the details.

Instead of binding the type to a type variable a, we could also bind it to _, in order to stress that we do not make use of this type.

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;
    }
  }
}
红尘作伴 2024-10-16 02:32:32

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

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 的类型推断出 root.leftroot.right 的类型,因此类型擦除并不会真正起作用在这里玩...

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

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;
    }
  }
}

Well, I run your code through the interpreter and I think it has nothing to do with type erasure. May be just some syntax error. Try this:

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;
    }
  }
}

You need to indicate the variable name that will be bound to the match, like n:Node[T]. That would give you a warning about type erasure, which you can remove by using n:Node[_]. The compiler can infer the type of root.left and root.right based on the type of root so type erasure doesn't really come into play here...

Note: I just checked the spec, the syntax for a type pattern is:

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

It would help if you provide the actual error message from the compiler, and the definition of Node and End as otherwise we need to infer all those things.


Edit:

Assuming you're compiling http://aperiodic.net/phil/scala/s-99/tree.scala, there is indeed a syntax error in your code. Use n:Node[_]. Then you'll get some type errors. Here is what works for me:

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;
    }
  }
}
幽蝶幻影 2024-10-16 02:32:32

为了在运行时匹配 Scala 中泛型的具体化类型,您需要使用 Manifests (qv) 编写代码的方式,将类型擦除。

In order to match the reified type at runtime for a generic in Scala, you need to use Manifests (q.v.) The way you wrote the code, the type is erased.

丿*梦醉红颜 2024-10-16 02:32:32

这种行为称为类型擦除。使用Manifests,您可以制定解决方法。请参阅

This behaviour is called type erasure. With Manifests you can make a workaround. See this question for more information.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文