Getting reference to a parameter of the outer func

2019-01-25 16:38发布

问题:

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.

回答1:

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)


回答2:

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


回答3:

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)
  }
}


标签: scala scope