Scala 中具有函数参数行为的奇怪隐式 def
Strange implicit def with function parameter behaviour in Scala
我用 Scala 编写了一个简单的代码,将 Function1 隐式转换为某种情况 class。
object MyApp extends App{
case class FunctionContainer(val function:AnyRef)
implicit def cast(function1: Int => String):FunctionContainer = new FunctionContainer(function1)
def someFunction(i:Int):String = "someString"
def abc(f : FunctionContainer):String = "abc"
println(abc(someFunction))
}
但是没用。编译器不想将 someFunction 作为参数传递给 abc。我能猜到它的原因,但不知道为什么它不起作用。
您的 someFunction
在这里显示为一种方法。
你可以试试
object MyApp extends App{
case class FunctionContainer(val function:AnyRef)
implicit def cast(function1: Int => String):FunctionContainer = new FunctionContainer(function1)
val someFunction = (i:Int) => "someString"
def abc(f : FunctionContainer):String = "abc"
println(abc(someFunction))
}
或
object MyApp extends App{
case class FunctionContainer(val function:AnyRef)
implicit def cast(function1: Int => String):FunctionContainer = new FunctionContainer(function1)
def someFunction(i:Int): String = "someString"
def abc(f : FunctionContainer):String = "abc"
println(abc(someFunction(_: Int)))
}
顺便说一句:隐式地将此类通用函数转换为其他函数会很快导致问题。你确定你需要这个吗?重载 abc
不是更容易吗?
你应该使用 eta-expansion
println(abc(someFunction _))
当您使用现有的方法名称时,编译器必须选择如何将方法类型转换为值。如果期望的类型是一个函数,那么它会扩展;否则它提供空括号来调用该方法。即描述here in the spec.
但并非总是如此。十年前,您只需使用方法名称即可获得函数值。
新的在线规范省略了 "Change Log" 附录,因此作为记录,这是有人对 parens 感到沮丧并介绍当前规则的时刻。 (参见 Scala 参考 2.9,第 181 页。)
这还没有消除所有irksome anomalies。
转化次数
方法到函数的隐式转换规则 (§6.26) 已经收紧。以前,用作值的参数化方法总是隐式转换为函数。当忘记方法参数时,这可能会导致意外结果。例如考虑下面的语句:
show(x.toString)
其中show定义如下:
def show(x: String) = Console.println(x)
很可能,程序员忘记为 toString 提供一个空参数列表 ()。以前的 Scala 版本会将这段代码视为部分应用的方法,并将其扩展为:
show(() => x.toString())
因此,将打印闭包的地址而不是 s 的值。仅当表达式的预期类型确实是函数类型时,Scala 2.0 版才会应用从部分应用方法到函数值的转换。例如,转换不会在上面的代码中应用,因为 show 的参数的预期类型是字符串,而不是函数类型。新的公约不允许一些以前的法律代码。示例:
def sum(f: int => double)(a: int, b: int): double =
if (a > b) 0 else f(a) + sum(f)(a + 1, b)
val sumInts = sum(x => x) // error: missing arguments
上面代码最后一行sum的部分应用不会转换为函数类型。相反,编译器将生成一条错误消息,指出缺少方法 sum 的参数。可以通过为部分应用程序提供预期类型来解决该问题,例如通过使用其类型注释 sumInts 的定义:
val sumInts: (int, int) => double = sum(x => x) // OK
另一方面,Scala 2.0 版现在会在必要时自动将带有空参数列表的方法应用于 () 参数列表。例如,上面的 show 表达式现在将扩展为
show(x.toString())
我用 Scala 编写了一个简单的代码,将 Function1 隐式转换为某种情况 class。
object MyApp extends App{
case class FunctionContainer(val function:AnyRef)
implicit def cast(function1: Int => String):FunctionContainer = new FunctionContainer(function1)
def someFunction(i:Int):String = "someString"
def abc(f : FunctionContainer):String = "abc"
println(abc(someFunction))
}
但是没用。编译器不想将 someFunction 作为参数传递给 abc。我能猜到它的原因,但不知道为什么它不起作用。
您的 someFunction
在这里显示为一种方法。
你可以试试
object MyApp extends App{
case class FunctionContainer(val function:AnyRef)
implicit def cast(function1: Int => String):FunctionContainer = new FunctionContainer(function1)
val someFunction = (i:Int) => "someString"
def abc(f : FunctionContainer):String = "abc"
println(abc(someFunction))
}
或
object MyApp extends App{
case class FunctionContainer(val function:AnyRef)
implicit def cast(function1: Int => String):FunctionContainer = new FunctionContainer(function1)
def someFunction(i:Int): String = "someString"
def abc(f : FunctionContainer):String = "abc"
println(abc(someFunction(_: Int)))
}
顺便说一句:隐式地将此类通用函数转换为其他函数会很快导致问题。你确定你需要这个吗?重载 abc
不是更容易吗?
你应该使用 eta-expansion
println(abc(someFunction _))
当您使用现有的方法名称时,编译器必须选择如何将方法类型转换为值。如果期望的类型是一个函数,那么它会扩展;否则它提供空括号来调用该方法。即描述here in the spec.
但并非总是如此。十年前,您只需使用方法名称即可获得函数值。
新的在线规范省略了 "Change Log" 附录,因此作为记录,这是有人对 parens 感到沮丧并介绍当前规则的时刻。 (参见 Scala 参考 2.9,第 181 页。)
这还没有消除所有irksome anomalies。
转化次数
方法到函数的隐式转换规则 (§6.26) 已经收紧。以前,用作值的参数化方法总是隐式转换为函数。当忘记方法参数时,这可能会导致意外结果。例如考虑下面的语句:
show(x.toString)
其中show定义如下:
def show(x: String) = Console.println(x)
很可能,程序员忘记为 toString 提供一个空参数列表 ()。以前的 Scala 版本会将这段代码视为部分应用的方法,并将其扩展为:
show(() => x.toString())
因此,将打印闭包的地址而不是 s 的值。仅当表达式的预期类型确实是函数类型时,Scala 2.0 版才会应用从部分应用方法到函数值的转换。例如,转换不会在上面的代码中应用,因为 show 的参数的预期类型是字符串,而不是函数类型。新的公约不允许一些以前的法律代码。示例:
def sum(f: int => double)(a: int, b: int): double =
if (a > b) 0 else f(a) + sum(f)(a + 1, b)
val sumInts = sum(x => x) // error: missing arguments
上面代码最后一行sum的部分应用不会转换为函数类型。相反,编译器将生成一条错误消息,指出缺少方法 sum 的参数。可以通过为部分应用程序提供预期类型来解决该问题,例如通过使用其类型注释 sumInts 的定义:
val sumInts: (int, int) => double = sum(x => x) // OK
另一方面,Scala 2.0 版现在会在必要时自动将带有空参数列表的方法应用于 () 参数列表。例如,上面的 show 表达式现在将扩展为
show(x.toString())