Вопрос

Паттерн сутенера-my-библиотека позволяет мне, по-видимому, добавить метод в класс, сделав доступное неявное преобразование из этого класса в тот, который реализует метод.

Однако я не допускает двух таких неявных конверсий, поэтому я не могу получить от A к C используя неявное A к B и еще один неявный B к C. Анкет Есть ли способ обойти это ограничение?

Это было полезно?

Решение

Scala имеет ограничение на автоматические преобразования, чтобы добавить метод, который состоит в том, что он не применяет более одного преобразования в попытке найти методы. Например:

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

Редактировать: View Bounds ('<%') устарели, поскольку Scala 2.11 https://issues.scala-lang.org/browse/si-7629 (Вместо этого вы можете использовать классы типов)

Однако, если неявное определение требует самого неявного параметра (просмотр Bound), Scala будут Ищите дополнительные неявные значения так долго, как это необходимо. Продолжить из последнего примера:

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

«Магия!», Вы можете сказать. Не так. Вот как компилятор переведет каждый:

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

Так что пока bToC используется как неявное преобразование, aToB а также toA передаются как неявные параметры, вместо того, чтобы быть цепью как неявные преобразования.

РЕДАКТИРОВАТЬ

Связанный вопрос интереса:

Другие советы

Обратите внимание, что вы также можете строить круги с неявными параметрами. Они, однако, обнаружены компилятором, как показано на этом:

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
}

Ошибка, предоставленная пользователю, не так ясны, как могли бы, хотя; это просто жалуется could not find implicit value for parameter Для всех трех строительных площадок. Это может скрыть основную проблему в менее очевидных случаях.

Вот Код, который также накапливает путь.

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))
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top