Scala 将 _ param 解释为 Any => [Any]
Scala interprets _ param as Any => [Any]
我有一个枚举定义如下
enum Operator[T](val expr: String, val tag: T):
case Plus(override val tag: T) extends Operator("+", tag)
case Minus(override val tag: T) extends Operator("-", tag)
case Multiply(override val tag: T) extends Operator("*", tag)
接下来是一个函数调用,它检查传递的运算符列表是否以某个运算符开头
def extract[A](expect: Operator[A], operators: List[Operator[A]]): Either[Error[A], (Operator[A], List[Operator[A]])] =
operators match {
case `expect` :: tail => Right(expect, operators.tail)
case _ =>
expect match {
case Plus(_) => Left(Error.ExpectPlus(operators))
case Minus(_) => Left(Error.ExpectMinus(operators))
case Multiply(_) => Left(Error.ExpectMultiply(operators))
}
}
但是当我用下面的参数调用函数时,我得到如下错误
extract(Plus(_), operators)
^^^^^^^^^^^^^^^
[error] | Found: Any => Operator[Any]
[error] | Required: Operator[Any]
谁能帮我解释一下为什么使用_作为参数会被解释为Any => [Any],有什么办法可以解决这个错误吗?
你写的和下面一样:
extract(x => Plus(x), operators)
// Same as:
extract(Plus(_), operators)
含义 Plus(_)
定义了一个函数,这不是 extract
所期望的。
这实际上是对@Luis Miguel Mejía Suárez 的评论和@Gaël J 的回答的补充。正如前面评论和答案中所述,您实际上是在将函数而不是 Operator
实例传递给提取函数。我认为您打算做的是对 Plus
中的标记使用通配符(当然这不是通配符,这会产生一个函数)。基于这些假设,我认为您正在寻找的是类型匹配。所以这需要一点重构,现在这段代码是用 Scala 2 编写的,但这些概念也应该非常适用于 Scala 3:
// I have defined the Operator as sealed abstract class earlier, and all the subtypes
sealed trait Err[OP <: Operator[_]]
object Err {
def apply[T <: Operator[_]]: Err[T] = new Err[T] {} // In Scala3 you can easily do type matching here
}
import scala.reflect.ClassTag
def extract[A, OperatorType <: Operator[A] : ClassTag](operators: List[Operator[A]]): Either[Err[OperatorType], (Operator[A], List[Operator[A]])] = {
operators match {
case (head : OperatorType) :: tail =>
Right(head, tail)
case _ => Left(Err[OperatorType])
}
}
val ops: List[Operator[Int]] = List(Plus(2), Minus(4), Multiply(7))
val shouldFail = extract[Int, Minus[Int]](ops) // fails since first element is not of type Minus
val shouldSucceed = extract[Int, Plus[Int]](ops) // succeeds
在scastie。
我有一个枚举定义如下
enum Operator[T](val expr: String, val tag: T):
case Plus(override val tag: T) extends Operator("+", tag)
case Minus(override val tag: T) extends Operator("-", tag)
case Multiply(override val tag: T) extends Operator("*", tag)
接下来是一个函数调用,它检查传递的运算符列表是否以某个运算符开头
def extract[A](expect: Operator[A], operators: List[Operator[A]]): Either[Error[A], (Operator[A], List[Operator[A]])] =
operators match {
case `expect` :: tail => Right(expect, operators.tail)
case _ =>
expect match {
case Plus(_) => Left(Error.ExpectPlus(operators))
case Minus(_) => Left(Error.ExpectMinus(operators))
case Multiply(_) => Left(Error.ExpectMultiply(operators))
}
}
但是当我用下面的参数调用函数时,我得到如下错误
extract(Plus(_), operators)
^^^^^^^^^^^^^^^
[error] | Found: Any => Operator[Any]
[error] | Required: Operator[Any]
谁能帮我解释一下为什么使用_作为参数会被解释为Any => [Any],有什么办法可以解决这个错误吗?
你写的和下面一样:
extract(x => Plus(x), operators)
// Same as:
extract(Plus(_), operators)
含义 Plus(_)
定义了一个函数,这不是 extract
所期望的。
这实际上是对@Luis Miguel Mejía Suárez 的评论和@Gaël J 的回答的补充。正如前面评论和答案中所述,您实际上是在将函数而不是 Operator
实例传递给提取函数。我认为您打算做的是对 Plus
中的标记使用通配符(当然这不是通配符,这会产生一个函数)。基于这些假设,我认为您正在寻找的是类型匹配。所以这需要一点重构,现在这段代码是用 Scala 2 编写的,但这些概念也应该非常适用于 Scala 3:
// I have defined the Operator as sealed abstract class earlier, and all the subtypes
sealed trait Err[OP <: Operator[_]]
object Err {
def apply[T <: Operator[_]]: Err[T] = new Err[T] {} // In Scala3 you can easily do type matching here
}
import scala.reflect.ClassTag
def extract[A, OperatorType <: Operator[A] : ClassTag](operators: List[Operator[A]]): Either[Err[OperatorType], (Operator[A], List[Operator[A]])] = {
operators match {
case (head : OperatorType) :: tail =>
Right(head, tail)
case _ => Left(Err[OperatorType])
}
}
val ops: List[Operator[Int]] = List(Plus(2), Minus(4), Multiply(7))
val shouldFail = extract[Int, Minus[Int]](ops) // fails since first element is not of type Minus
val shouldSucceed = extract[Int, Plus[Int]](ops) // succeeds
在scastie。