Scala 应用方法调用,因为括号与隐式参数冲突 [英] Scala apply method call as parentheses conflicts with implicit parameters

查看:26
本文介绍了Scala 应用方法调用,因为括号与隐式参数冲突的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Cay Horstmann 的书不耐烦的 Scala"中有关于 apply 方法的注释:

There is a note in Cay Horstmann's book "Scala for the Impatient" about the apply method:

有时,() 符号会与另一个 Scala 特性冲突:隐式参数.例如,表达式 "Bonjour".sorted(3)产生错误,因为可以选择调用排序方法有一个排序,但 3 不是一个有效的排序.

Occasionally, the () notation conflicts with another Scala feature: implicit parameters. For example, the expression "Bonjour".sorted(3) yields an error because the sorted method can optionally be called with an ordering, but 3 is not a valid ordering.

解决方案是将 "Bonjour".sorted 分配给一个变量并对其调用 apply,例如:

The solution is to assign "Bonjour".sorted to a variable and call apply on it, for example:

val result = "Bonjour".sorted
result(3)

或者明确调用apply:

Or call apply explicitly:

"Bonjour".sorted.apply(3)

但是为什么这不起作用并产生编译错误:

But why this doesn't work and produces a compile error:

("Bonjour".sorted)(3)

sorted 方法返回一个String,可以隐式转换为StringOps,并用括号包裹字符串表达式.为什么编译器不接受调用 StringOps 的 apply 方法?

The sorted method returns a String, which can be imlicitly converted to a StringOps and parentheses are used to wrap the string expression. Why compiler doesn't accept to call the apply method of a StringOps?

推荐答案

可以使用 -Xprint:parser 来查看括号是否提前丢弃:

You can use -Xprint:parser to see that the parens are discarded early:

scala> implicit class x(val s: String) { def scaled(implicit i: Int) = s * i }
defined class x

scala> "hi".scaled(5)
res0: String = hihihihihi

scala> { implicit val n: Int = 5 ; "hi".scaled }
res1: String = hihihihihi

scala> "hi".scaled(5)(3)
res2: Char = i

scala> { implicit val n: Int = 5 ; ("hi".scaled)(3) }
res3: String = hihihi

scala> :se -Xprint:parser

scala> { implicit val n: Int = 5 ; ("hi".scaled)(3) }
[[syntax trees at end of                    parser]] // <console>
package $line8 {
  object $read extends scala.AnyRef {
    def <init>() = {
      super.<init>();
      ()
    };
    object $iw extends scala.AnyRef {
      def <init>() = {
        super.<init>();
        ()
      };
      import $line3.$read.$iw.$iw.x;
      object $iw extends scala.AnyRef {
        def <init>() = {
          super.<init>();
          ()
        };
        val res4 = {
          implicit val n: Int = 5;
          "hi".scaled(3)
        }
      }
    }
  }
}

res4: String = hihihi

scala> 

额外的括号什么也不做.编译器只看到一个应用程序expr(args).因为它是一个应用程序,所以你不会得到隐式应用程序"的转换.

The extra parens do nothing. The compiler just sees an application expr(args). Because it's an application, you don't get "implicit application" conversion.

无论如何,scaled这个方法的含义取决于预期的类型.

In any case, the meaning of scaled, a method, depends on the expected type.

我们期望额外的括号会有所作为的原因是括号会覆盖运算符的优先级.但是 (x) 只是 x.

The reason we expect the extra parens to make a difference is that parens override precedence of operators. But (x) is just x.

可能规范实际上对此很清楚:

Possibly the spec is actually clear about this:

e(args) 要求 e 适用于 args.特别是根据e的参数类型对args进行类型检查.

e(args) requires that e be applicable to the args. In particular, the args are typechecked according to the parameter types of e.

e(args) 被当作 e.apply(args) 如果 e 是一个值,但是 scaled是一种方法.

e(args) is taken as e.apply(args) if e is a value, but scaled is a method.

您希望隐式应用程序"插入隐式参数,但这仅适用于尚未应用 e 的情况.或者,(e)(args) 可以看作 (e(_))(args),即 (x => e(x))(arg).

You're hoping for "implicit application" to insert the implicit args, but that only applies when e is not already applied. Or that (e)(args) could be taken as (e(_))(args), that is, (x => e(x))(arg).

当写成 e.apply(arg) 时,e 不是像 e(arg) 这样的应用程序,所以你可以从转换如隐式应用.

When written as e.apply(arg), the e is not an application like e(arg), so you benefit from conversions like implicit application.

这篇关于Scala 应用方法调用,因为括号与隐式参数冲突的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆