首页 > 解决方案 > 模式匹配 - 值不是绑定变量的成员

问题描述

我正在通过 Scala (ver. 2.13.2) 工作,在这里我定义了一个带有 trait 的简单链表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会略有不同(没有大括号),但这不是这里的重点。

问题

为什么在一种情况下会出错,而在另一种情况下却可以愉快地编译?

标签: scalacompiler-errorspattern-matchingscala-compiler

解决方案


它返回一个错误,因为它是在中定义elemSequence的方法,所以它在 中不可见。privateListSeqListPair

一种解决方案可能是将可见性更改为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 == "[]")
}

推荐阅读