scala: переопределить неявный параметр вокруг блока кода вызова по имени - PullRequest
4 голосов
/ 13 мая 2011

Есть ли способ переопределить неявный параметр, используемый функциями, вызываемыми внутри блока структуры управления? У меня есть код, который выглядит следующим образом:

def g()(implicit y: Int) {
  // do stuff with y
}

class A {
  implicit val x: Int = 3

  def f() {
    overrideImplicit(...) { // <-- overrideImplicit() is permitted to do anything it wants make it so that g() sees a different implicit val, as long as we do not explicitly declare "implicit" here (though it could happen within the method/function)
      g() // somehow sees the new implicit as opposed to x
    }
  }
}

Насколько я понимаю, даже если overrideImplicit () устанавливает неявное внутри себя, g () все равно увидит тот, который находился в области действия в тот момент, который объявлен в A. Я понимаю, что один из способов получить желаемое поведение - явно указать «неявный val x2: Int = 4» внутри f (), но я хочу избежать этого и скрыть тот факт, что используются имплициты. Есть какой-либо способ сделать это? Спасибо.

Ответы [ 3 ]

6 голосов
/ 13 мая 2011

В настоящее время это делается в STM, как это:

implicit object globalCtx extends Ctx
val r = ref(0)

atomic { implicit txn =>
  r := 5 // resolves `txn` as the implicit parameter instead of globalCtx
}

так что, насколько мне известно, лучшего способа сделать это не существует. По крайней мере, пока - смотрите это обсуждение о типах SAM (Single Abstract Method) и, возможно, добавлении их в Scala. Предполагается, что в какой-то момент SAM-замыкания могли бы решить эту проблему, если бы они были реализованы таким образом, чтобы последствия внутри SAM-замыкания снова разрешались в контексте целевого типа.

1 голос
/ 13 мая 2011

Я бы действительно усомнился в причинах, почему вы хотели бы сделать такую ​​вещь, поскольку я уверен, что это может привести к неожиданному поведению в будущем.

Если вы можете жить с x как var, хотя (и доступным из определения overrideImplicit), это может приблизить вас к

def overrideImplicit(i:Int)(block: =>Unit) = {
  val old = x
  x = i
  block
  x = old
}
0 голосов
/ 13 мая 2011

Я не уверен, как это сделать, но я также не думаю, что это хорошая идея, учитывая, что вы не можете использовать две разные переменные одного типа, и учитывая, что даже если вы получили чтобы это работало, для многих людей не было бы очевидно, каково было ожидаемое поведение. Вы рассматривали возможность использования изменяемого стека вместо этого? Что-то вроде

object Example {
  private[this] val stack = collection.mutable.ArrayStack[Int](0)
  def g() { println(stack.top) }
  def using(i: Int)(f: => Unit) { stack push i; f; stack pop }
  def f() {
    using(1) { g }
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...