Domanda

Il modello magnaccia-my-biblioteca mi permette di aggiungere un metodo apparentemente ad una classe mettendo a disposizione una conversione implicita da quella classe a uno che implementa il metodo.

Scala non consente due tali conversioni implicite in atto, però, quindi non posso ottenuto da A a C utilizzando un A implicito B e un altro B implicita C. C'è un modo per aggirare questa limitazione?

È stato utile?

Soluzione

Scala ha una restrizione conversioni automatiche per aggiungere un metodo, che è che non applicherà più di una conversione nel tentativo di trovare metodi. Ad esempio:

class A(val n: Int)
class B(val m: Int, val n: Int)
class C(val m: Int, val n: Int, val o: Int) {
  def total = m + n + o
}

// This demonstrates implicit conversion chaining restrictions
object T1 { // to make it easy to test on REPL
  implicit def toA(n: Int): A = new A(n)
  implicit def aToB(a: A): B = new B(a.n, a.n)
  implicit def bToC(b: B): C = new C(b.m, b.n, b.m + b.n)

  // won't work
  println(5.total)
  println(new A(5).total)

  // works
  println(new B(5, 5).total)
  println(new C(5, 5, 10).total)
}

EDIT: View limiti ( '<%') sono deprecati dal Scala 2.11 https://issues.scala-lang.org/browse/SI-7629 (È possibile utilizzare le classi di tipo invece)

Tuttavia, se una definizione implicita richiede un parametro implicito in sé (View legato), Scala look per valori impliciti aggiuntivi per tutto il tempo necessario. Continuare dall'ultimo esempio:

// def m[A <% B](m: A) is the same thing as
// def m[A](m: A)(implicit ev: A => B)

object T2 {
  implicit def toA(n: Int): A = new A(n)
  implicit def aToB[A1 <% A](a: A1): B = new B(a.n, a.n)
  implicit def bToC[B1 <% B](b: B1): C = new C(b.m, b.n, b.m + b.n)

  // works
  println(5.total)
  println(new A(5).total)
  println(new B(5, 5).total)
  println(new C(5, 5, 10).total)
}

"Magic!", Si potrebbe dire. Non così. Ecco come il compilatore tradurrebbe ognuno:

object T1Translated {
  implicit def toA(n: Int): A = new A(n)
  implicit def aToB(a: A): B = new B(a.n, a.n)
  implicit def bToC(b: B): C = new C(b.m, b.n, b.m + b.n)

  // Scala won't do this
  println(bToC(aToB(toA(5))).total)
  println(bToC(aToB(new A(5))).total)

  // Just this
  println(bToC(new B(5, 5)).total)

  // No implicits required
  println(new C(5, 5, 10).total)
}

object T2Translated {
  implicit def toA(n: Int): A = new A(n)
  implicit def aToB[A1 <% A](a: A1): B = new B(a.n, a.n)
  implicit def bToC[B1 <% B](b: B1): C = new C(b.m, b.n, b.m + b.n)

  // Scala does this
  println(bToC(5)(x => aToB(x)(y => toA(y))).total)
  println(bToC(new A(5))(x => aToB(x)(identity)).total)      
  println(bToC(new B(5, 5))(identity).total)

  // no implicits required
  println(new C(5, 5, 10).total)
}

Così, mentre bToC viene utilizzato come una conversione implicita, aToB e toA vengono passati come parametri impliciti , invece di essere incatenato come conversioni implicite.

Modifica

questione connessa di interesse:

Altri suggerimenti

Si noti che si può costruire cerchi con parametri impliciti, anche. Questi sono, tuttavia, rilevato dal compilatore, come presentato da questo:

class Wrap {
  class A(implicit b : B)
  class B(implicit c : C)
  class C(implicit a : A)

  implicit def c = new C
  implicit def b = new B
  implicit def a = new A
}

L'errore (s) trasmesso all'utente non è chiaro come potrebbero essere, comunque; solo lamenta could not find implicit value for parameter per tutti e tre sito di costruzione. Questo potrebbe oscurare il problema di fondo nei casi meno evidenti.

Ecco un codice che si accumula anche il percorso.

import scala.language.implicitConversions

// Vertices
case class A(l: List[Char])
case class B(l: List[Char])
case class C(l: List[Char])
case class D(l: List[Char])
case class E(l: List[Char])

// Edges
implicit def ad[A1 <% A](x: A1) = D(x.l :+ 'A')
implicit def bc[B1 <% B](x: B1) = C(x.l :+ 'B')
implicit def ce[C1 <% C](x: C1) = E(x.l :+ 'C')
implicit def ea[E1 <% E](x: E1) = A(x.l :+ 'E')

def pathFrom(end:D) = end

pathFrom(B(Nil))   // res0: D = D(List(B, C, E, A))
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top