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

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

问题描述

Cay Horstmann的书不耐烦的斯卡拉"中有一条关于应用方法的注释:

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分配给变量,然后对其应用调用,例如:

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

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

或致电明确申请:

"Bonjour".sorted.apply(3)

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

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

("Bonjour".sorted)(3)

已排序的方法返回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.

我们期望额外的paren有所作为的原因是parens会覆盖运算符的优先级.但是(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时适用.或者,可以将(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编写为e.apply(arg)时,它不是像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天全站免登陆