【问题标题】:Scala case classes and listsScala 案例类和列表
【发布时间】:2011-08-15 19:43:59
【问题描述】:

我对 Scala 完全陌生。现在,我正在尝试将我在标准 ML 中编写的解析器移植到 Scala,但遇到以下代码问题:

abstract class Token
case class Zero extends Token
case class At extends Token
//...

object Tokenizer {
  def tokenize(seq : List[Char]) : List[Token] = seq match {
    case List() => error("Empty input")
    case '0' :: rest => Zero :: tokenize(rest)
    case '@' :: rest => At :: tokenize(rest)
    //...
  }  
}

在 SML 中,我不必声明 tokenize() 方法的返回类型,但似乎 Scala 需要它,并且它对我提供的类型不满意(它抱怨零,At 是无效类型,并且它们应该是 Token 类型)。请注意,我还想在解析阶段稍后的时间点对令牌列表进行模式匹配。

我在网上和 stackoverflow 上进行了一些搜索,以查看之前是否有人提出过类似的问题(看起来很简单),但不知何故我找不到任何东西。我很确定我有一些基本错误,请随时赐教:)

【问题讨论】:

    标签: list scala type-inference case-class


    【解决方案1】:

    AtZero 是类,而不是对象,因此它们本身不是Token 的实例。您可以通过将case class 更改为case object 来修复您的代码:

    case object Zero extends Token
    case object At extends Token
    

    之所以需要指定函数的返回类型是因为 Scala 的编译器无法确定递归函数的类型,您可以在此处阅读更多内容:Why does Scala require a return type for recursive functions?

    【讨论】:

    • 谢谢,但object 修饰符不会生成ZeroAt 单例类型吗?我想多次实例化它们。
    • 是的,每个只有一个实例。但是您不会在代码中实例化它们,而是将它们用作对象,所以我认为这就是您想要的。否则,只需将new 放在AtZero 前面,一切都会正常工作(或以() 为后缀)。除非您将某些状态与每个实例相关联,否则创建多个实例会很浪费,不是吗?
    • 你是对的。我过度简化了代码并删除了我的一些状态。对于那个很抱歉。非常感谢您的解释。
    【解决方案2】:

    如果你想创建ZeroAt case 类的新实例,那么你应该使用apply 工厂方法来实例化它们(或new 关键字:new Zero),像这样(在 Scala Zero() 将等于 Zero.apply()):

    case '0' :: rest => Zero() :: tokenize(rest)
    

    如果你只写Zero(而不是Zero()),那么你使用的是Zero类的伴随对象,它是由编译器自动创建的。

    【讨论】:

    • 我自己是 scala 的新手,我想知道为什么在这种情况下它不能编译?你是说你不能使用(自动生成的)伴生对象进行模式匹配吗?如果是这样,为什么不呢?
    • @Droggl:当您在模式匹配中使用Zero 时,将使用Zero.unapply(...) 方法(该方法也会为案例类的伴随对象自动生成),因此您可以 在模式匹配中使用Zero。问题是伴随对象不扩展 Token 类 - 只有 Zero class 扩展它。并且生成的 List 的所有元素都应该属于 Token 类。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 2017-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多