2015-12-08 2 views
2

Учитывая следующий код:Каковы правила в Scala для решения противоречивых неявные значения

/** 
    * Created by danap on 12/8/15. 
    */ 
object ImplicitTest { 
    trait EC { 
    override def toString : String = s"EC" 
    } 

    trait DEC extends EC { 
    def sub : EC 
    override def toString : String = s"DEC - $sub" 
    } 

    def usesEC(implicit ec : EC) = ec.toString 

    class B(implicit val dec: DEC) { 
    def whichEC = usesEC 
    } 

    class C(implicit val dec: DEC) { 
    implicit val _ec = dec.sub 

    def whichEC = usesEC 
    def whichECExplicit = usesEC(_ec) 
    } 

    def main(args:Array[String]): Unit = { 

    implicit val dec : DEC = new DEC { 
     val sub = new EC {} 
    } 

    val b = new B 
    val c = new C 

    println(s"b class = ${b.whichEC}") 
    println(s"c class = ${c.whichEC}") 
    println(s"c class = ${c.whichECExplicit}") 
    } 
} 

Выход для Скале 2.11:

b class = DEC - EC 
c class = DEC - EC 
c class = EC 

Я ожидал, что это будет:

b class = DEC - EC 
c class = EC 
c class = EC 

Поскольку неявный val _ec объявлен «ближе» к вызову usesEC в whichEC. Почему это происходит? Кроме того, как я могу заставить _ec использовать неявно в C.whichEC?

+1

Персональное правило №1 при использовании implicits в scala: никогда не имеет в области более одного типа, потому что вы никогда не знаете, кто переопределяет кого. –

ответ

2

победы подтипа:

class Super    { override def toString = "Super" } 
class Sub extends Super { override def toString = "Sub" } 

// does not compile - ambiguous 
object Test1 { 
    implicit val s1 = new Super 
    implicit val s2 = new Super 

    println(implicitly[Super]) 
} 

// does not compile - ambiguous 
object Test2 { 
    implicit val s1 = new Sub 
    implicit val s2 = new Sub 

    println(implicitly[Super]) 
} 

object Test3 { 
    implicit val s1 = new Super 
    implicit val s2 = new Sub 

    println(implicitly[Super]) 
} 

Test3 // 'Sub' 

правило для разрешения неявных параметров определяются в §7.2 of the Scala Language Specification:

Если есть несколько правомочных аргументов, которые соответствуют типу неявному параметру, наиболее характерном один будет выбран с использованием правил статического разрешения перегрузки.

Ссылка на §6.26.3, которая касается вывода типа. Здесь тип A <: B дает альтернативный подкласс A a относительный вес 1 над альтернативным суперклассом B, что делает Aболее конкретно чем B.


В общем, как комментарий предполагает, следует избегать в результате чего несколько неквалифицированных членов (префикс меньше, т.е. неявные значения, которые находятся в местах, по умолчанию, например, через компаньона объекты) в область видимости.

Смежные вопросы