Getting reference to a parameter of the outer func

2019-01-25 17:12发布

Please consider this code:

trait A {
  def a : Int
}

def f ( a : Int ) = {
  def a0 = a
  new A {
    def a = a0
  }
}

The problem is quite evident: def a0 = a is a typical annoying boilerplate code and the situation only worsens when more parameters get introduced.

I am wondering if it's possible to somehow get a direct reference to the a variable of the outer scope inside the declaration of the instance of the trait and thus to get rid of the intermediate a0.

Please keep in mind that changing name of input parameter of the function is not allowed as is changing the trait.

标签: scala scope
3条回答
够拽才男人
2楼-- · 2019-01-25 17:18

Here is an anonymous solution.

package eyeshadow

trait A {
  def a: Int
}

class B {
  def f(a: Int) = {
    val fa: A = new {
      //private val b = a
      private[this] val b = a // crashes, sorry scalac. edit: ok in 2.11
    } with A {
      def a = b
    }
    fa.a
    /*
     * This seems far-fetched, but compare the initial objections in
     * https://issues.scala-lang.org/browse/SI-3836
     * All I want is to alias a symbol, right?
     * Maybe the override means "do not shadow."
    val fa: A = new A {
      //import fa.{ a => b }
      import this.{ a => b }
      override def b = a
    }
     */
  }
}

object Test {
  def main(args: Array[String]) {
    val b = new B
    println(b f 7)
  }
}
查看更多
在下西门庆
3楼-- · 2019-01-25 17:24

I think the closest you can get to (without changing your API) is:

def f(a: Int) = {
  def ff(a0: Int) = {
    new A {
      def a = a0
    }
  }
  ff(a)
}

In Scala, methods are not types. Thus, it is not possible to reference them with the type system or any of there members.

scala> class X{def f = 0}
defined class X

scala> import reflect.runtime.universe._
import reflect.runtime.universe._

scala> typeOf[X].member(newTermName("f")).isType
res9: Boolean = false
查看更多
劳资没心,怎么记你
4楼-- · 2019-01-25 17:36

I don't think there is direct way to do that, because it would require some special (hypothetical) identifier thisMethod. However, depending on your context, the following two ways to avoid the name shadowing might be possible:

(1) Replace anonymous class A with implementing class:

case class AImpl(a: Int) extends A

def f(a : Int): A = AImpl(a)

(2) Define f in an abstract trait and use a concrete implementation for it:

trait F {
  def f(a: Int): A
}

object FImpl extends F {
  def f(a0: Int): A = new A { val a = a0 }
}

def test(factory: F): A = factory.f(a = 33)
查看更多
登录 后发表回答