假设我使用隐式默认参数定义了以下函数,如下所示:
val isValid: Any => Option[String] = _ => None
def input[T](f: () => T)(implicit validate: T => Option[String] = isValid) = {
val t = f()
println("Got value: " + t)
if (validate != isValid) {
println("Validating: " + validate(t))
}
}
这可以按预期工作,直到我将选项作为参数化类型传递:
input(() => "Text")
input(() => 3)
input(() => Some("Text"))
给我以下输出:
有价值:文字
有价值:3
有价值:有些(文字)
验证:部分(文字)
当我将Option [String]传递给我的函数时,我对有关如何失败感到困惑。为什么isValid比较失败以及它可以调用哪个验证函数?
答案 0 :(得分:3)
标准库提供A =:= B
证据,证明A
和B
类型相同。 A =:= B
是A => B
的子类型。因此,当您要求隐式Option[String] => Option[String]
scalac找到Option[String] =:= Option[String]
的隐式实例时。
答案 1 :(得分:3)
隐式参数由其签名标识,在这种情况下,该签名为T => Option[String]
。在调用input
的范围内,编译器正在获取Option[String] => Option[String]
函数(正如其他海报所指出的那样)。
如果要更改该行为,可能需要考虑为隐式值创建新类型。像这样的东西会起作用:
case class Validator[T](v: T => Option[String])
然后您将如下声明input
(与通用方法的默认值相比较麻烦):
def input[T](f: () => T)(implicit validate: Validator[T]) = {
val t = f()
println(s"Got value: $t")
val result = validate.v(t)
println(s"Got validation result: $result")
}
您现在可以为不同类型的T提供验证器。这是默认的Option[String]
验证器:
implicit val defaultIsValidOptionString = Validator[Option[String]](_ => None)
请注意,您可能必须在调用输入时显式声明类型(因为它会将T
推断为Some[String]
,而不是Option[String]
):
input[Option[String]](() => Some("Text"))
或者更简单地说:
input(() => Option("Text"))
默认隐式值(类型擦除允许)将与input
进入相同的范围(例如在相同的类/对象/特征/包对象中),并且您可以在调用input
的代码中覆盖它们。
答案 2 :(得分:0)
在第三种情况下,范围中存在隐式Option[String] => Option[String]
,即身份。
事实上,如果A <: B
,函数(x: A) => x: B
始终在范围内。
比较检查两个函数是否相等有点复杂。从数学上讲,这只能在所有可能的值上进行检查,但对于大多数类型而言,这不是计算可行的(您可以将其用于Boolean
或Unit
)。