【问题标题】:Pattern matching - value is not a member on a bound variable模式匹配 - 值不是绑定变量的成员
【发布时间】:2021-07-24 10:00:33
【问题描述】:

我正在使用 Scala (ver. 2.13.2),在这里我定义了一个简单的链表,其特征为 ListSeq。另外,我想重写一个toString 方法来进行漂亮的打印。为此,我决定使用模式匹配。在assert 案例中可以看到想要的结果

sealed trait ListSeq {
    override def toString: String = s"[$elemSequence]"
    private def elemSequence: String = {
        this match {
            case ListPair(hd, tl @ ListPair(_, _)) => s"$hd, ${tl.elemSequence}"
            case ListPair(hd, EmptyList) => s"$hd"
            case EmptyList => ""
        }
    }
}
case class ListPair(head: Int, tail: ListSeq) extends ListSeq
case object EmptyList extends ListSeq

object ListSeqExample extends App {
    val seq1 = ListPair(1, ListPair(2, ListPair(3, EmptyList)))
    val seq2 = EmptyList
    
    assert(seq1.toString == "[1, 2, 3]")
    assert(seq2.toString == "[]")
}

问题

这段代码没有编译,错误是:

value elemSequence is not a member of ListPair
            case ListPair(hd, tl @ ListPair(_, _)) => s"$hd, ${tl.elemSequence}"

我不清楚为什么会出现此错误。据我所知,Scala 可以匹配嵌套字段并将字段绑定到变量——就像在case ListPair(hd, tl @ ListPair(_, _)) 中所做的那样。但是从报错信息来看,似乎无法猜测绑定对象的类型(ListPair

奇怪的行为

另一个有趣的事情是 - 如果我以以下方式重新定义 ListSeq - 通过删除 elemSequence 方法,并且所有字符串创建都在 toString 中完成 - 没有错误

sealed trait ListSeq {
    override def toString: String = this match {
        case ListPair(hd, tl @ ListPair(_, _)) => s"$hd, ${tl.toString}"
        case ListPair(hd, EmptyList) => s"$hd"
        case EmptyList => ""
    }
}

我知道toString的结果会略有不同(没有大括号),但这不是这里的重点。

问题

为什么在一种情况下会出错,而在另一种情况下却能顺利编译?

【问题讨论】:

    标签: scala compiler-errors pattern-matching scala-compiler


    【解决方案1】:

    它返回一个错误,因为elemSequence 是在ListSeq 中定义的private 方法,因此它在ListPair 中不可见。

    一种解决方案可能是将可见性更改为 protected(并添加修饰符 final 以使子类无法 override 方法):

    sealed trait ListSeq {
        override def toString: String = s"[$elemSequence]"
        final protected def elemSequence: String = {
            this match {
                case ListPair(hd, tl @ ListPair(_, _)) => s"$hd, ${tl.elemSequence}"
                case ListPair(hd, EmptyList) => s"$hd"
                case EmptyList => ""
            }
        }
    }
    case class ListPair(head: Int, tail: ListSeq) extends ListSeq
    case object EmptyList extends ListSeq
    
    object ListSeqExample extends App {
        val seq1 = ListPair(1, ListPair(2, ListPair(3, EmptyList)))
        val seq2 = EmptyList
        
        assert(seq1.toString == "[1, 2, 3]")
        assert(seq2.toString == "[]")
    }
    

    【讨论】:

      【解决方案2】:

      这是一个私有方法。这些不能被子类继承或访问(在 Scala 或 Java 中)。

      将其更改为受保护或公共或包私有将解决此问题。

      【讨论】:

        猜你喜欢
        • 2013-05-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多