让我们说我已定义了这些类(这是我的代码的简化版本)
sealed trait Expression
trait ExpressionA extends Expression
trait ExpressionB extends Expression
case class OperationA(op: String, a: ExpressionA, b:ExpressionA) extends ExpressionA
case class OperationB(op: String, a: ExpressionB, b:ExpressionB) extends ExpressionB
case class ComparisonB(op: String, a: ExpressionA, b:ExpressionA) extends ExpressionB
case class VariableA(op: String, a: ExpressionA) extends ExpressionA
然后我想要替换VariableA类中的给定字符串 所以我可以写
def replace(exp: ExpressionB, operation: String => String): ExpressionB = exp match {
case ComparisonB(op, a, b) => ComparisonB(op, replace(a, operation), replace(b, operation))
case OperationB(op, a, b) => OperationB(op, replace(a, operation), replace(b, operation))
}
def replace(exp: ExpressionA, operation: String => String): ExpressionA = exp match {
case OperationA(op, a, b) => OperationA(op, replace(a, operation), replace(b, operation))
case VariableA(name) => VariableA(operation(name))
}
但我想将这两个函数合并为一个泛型类型。
这是我试过的
def replace[T <: Expression](exp:T, operation: String => String):T = exp match {
case ComparisonB(op, a, b) => ComparisonB(op, replace(a, operation), replace(b, operation))
case OperationB(op, a, b) => OperationB(op, replace(a, operation), replace(b, operation))
case OperationA(op, a, b) => OperationA(op, replace(a, operation), replace(b, operation))
case VariableA(name) => VariableA(operation(name))
}
我收到错误
Expression of type ExpressionA does not conform to expected type T
尽管理论上它总是和输入的类型相同。所以我不知道我的代码有什么问题,它是否缺少一些含义,或者错误的方法呢?
答案 0 :(得分:2)
如果您希望replace
的返回类型依赖于exp
的值(即exp
是否与特定模式匹配),那么实际上您需要polymorphic函数。
trait Replacer[T <: Expression] {
def replace(exp: T, operation: String => String): T
}
object Replacer {
implicit val exprA: Replacer[ExpressionA] =
(exp: ExpressionA, operation: String => String) => exp match {
case OperationA(op, a, b) => OperationA(op, replace(a, operation), replace(b, operation))
case VariableA(name) => VariableA(operation(name))
}
implicit val exprB: Replacer[ExpressionB] =
(exp: ExpressionB, operation: String => String) => exp match {
case ComparisonB(op, a, b) => ComparisonB(op, replace(a, operation), replace(b, operation))
case OperationB(op, a, b) => OperationB(op, replace(a, operation), replace(b, operation))
}
}
def replace[T <: Expression](exp: T, operation: String => String)(implicit replacer: Replacer[T]): T =
replacer.replace(exp, operation)
答案 1 :(得分:1)
在Scala match
表达式中,返回所有情况的公共类型。在示例中,您提供的常见类型为Expression
而不是T
,因此会出现编译错误。
您可以将返回类型定义为Expression
或(如果要保留传递给方法的类型,请将替换保存为Expression
的实例方法,即def replace(operation: String => String): Expression
并覆盖它在类中替换返回类型,例如def replace(operation: String => String): OperationA