在 Scala 2.11.7 中,具有以下 case 类和一个额外的 apply
方法:
case class FieldValidator[T](key: String, isValid: T => Boolean,
errorMessage: Option[String] = None)
object FieldValidator {
def apply[T](key: String, isValid: T => Boolean,
errorMessage: String): FieldValidator[T] = ???
}
当我尝试使用:
FieldValidator[String](key, v => !required || v.nonEmpty, "xxx")
我收到指向
v
的“缺少参数类型”编译错误.当我明确指定
v
的类型时,它编译得很好,我什至可以跳过 apply
的泛型类型方法,即FieldValidator(key, (v: String) => !required || v.nonEmpty, "xxx")
为什么不是
v
的类型当只是 apply
的泛型类型时推断提供?
最佳答案
这不是关于泛型,而是重载和默认参数的问题。
首先,回想一下,自从 FieldValidator
是 case
-class,合成工厂方法
def apply(
key: String,
isValid: T => Boolean,
errorMessage: Option[String] = None
)
自动添加到伴随对象
FieldValidator
.这导致 Field
验证器具有两个具有默认参数和相同名称的通用方法。这是一个较短的示例,其行为方式大致相同:
def foo[A](f: A => Boolean, x: Int = 0): Unit = {}
def foo[A](f: A => Boolean, x: String): Unit = {}
foo[String](_.isEmpty)
结果是:
error: missing parameter type for expanded function ((x$1: ) => x$1.isEmpty)
foo[String](_.isEmpty) ^
我无法确定到底出了什么问题,但本质上,您通过向编译器抛出三种不同类型的多态性而混淆了太多的歧义:
apply
的方法[A]
errorMessage
( x
在我较短的例子中)可以省略。 总之,这使编译器可以在两个同名方法之间进行选择,这些方法具有不清楚的类型和不清楚的预期类型参数数量。虽然灵活性是好的,但太多的灵活性就是太多了,编译器放弃试图弄清楚你想要什么,并强制你明确指定每个参数的所有类型,而不依赖于推理。
从理论上讲,它可以在这种特殊情况下解决这个问题,但这需要更复杂的推理算法和更多的回溯和反复试验(这会减慢一般情况下的编译速度)。你不希望编译器花半天时间玩 typesystem-sudoku,即使它理论上可以找到一个独特的解决方案。快速退出并显示错误消息是一个合理的选择。
解决方法
作为一种简单的解决方法,请考虑以允许编译器尽快消除歧义的方式重新排序参数。例如,将参数拆分为两个参数列表,其中两个
String
s 首先出现,将使其明确:case class FieldValidator[T](
key: String,
isValid: T => Boolean,
errorMessage: Option[String] = None
)
object FieldValidator {
def apply[T]
(key: String, errorMessage: String)
(isValid: T => Boolean)
: FieldValidator[T] = {
???
}
}
val f = FieldValidator[String]("key", "err"){
s => s.nonEmpty
}
关于scala - 为什么不能推断泛型函数的参数类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54347455/