2017-08-21 1 views
0

Ich versuche, einen generischen impliziten Anbieter zu machen, die einen impliziten Wert für einen bestimmten Typen, etwas in den Zeilen erstellen:Importieren generic implicits von Klasseninstanzen

trait Evidence[T] 

class ImplicitProvider[T] { 
    class Implementation extends Evidence[T] 
    implicit val evidence: Evidence[T] = new Implementation 
} 

diese impliziten zu verwenden, ich erstellen eine val provider = new ImplicitProvider[T] Instanz wo notwendig und importieren Sie daraus import provider._. Dies funktioniert, solange es nur eine Instanz gibt. Doch manchmal implicits für verschiedene Arten an einem Ort benötigt

case class A() 
case class B() 

class Test extends App { 
    val aProvider = new ImplicitProvider[A] 
    val bProvider = new ImplicitProvider[B] 

    import aProvider._ 
    import bProvider._ 

    val a = implicitly[Evidence[A]] 
    val b = implicitly[Evidence[B]] 
} 

Und dies nicht gelingt mit could not find implicit value for parameter und not enough arguments for method implicitly Fehler zu kompilieren.

Wenn ich implizite Vals von Providern direkt verwende, fängt alles wieder an zu arbeiten.

implicit val aEvidence = aProvider.evidence 
implicit val bEvidence = bProvider.evidence 

Jedoch versuche ich einzelne Werte zu vermeiden, importieren, da es tatsächlich mehrere implicits in jedem Provider ist und das Ziel ist es, sie wenn möglich zu abstrahieren.

Kann dies irgendwie erreicht werden oder will ich zu viel vom Compiler?

Antwort

1

Das Problem ist, dass, wenn Sie von beiden Objekte importieren, sind Sie in zwei Entitäten zu bringen, die kollidierenden Namen haben: evidence in aProvider und evidence in bProvider. Der Compiler kann diese nicht disambiguieren, sowohl wegen seiner Implementierung als auch, weil es eine schlechte Idee für implizite Dinge wäre, die bereits geheimnisvoll sein können, Dinge tun zu können, die nicht explizit getan werden können (Disambiguierung zwischen kollidierenden Namen).

Was ich nicht verstehe, ist was der Punkt ImplicitProvider ist. Sie können die Implementation Klasse auf die oberste Ebene ziehen und eine object irgendwo haben, die die implicit val s enthält.

class Implementation[T] extends Evidence[T] 

object Evidence { 
    implicit val aEvidence: Evidence[A] = new Implementation[A] 
    implicit val bEvidence: Evidence[B] = new Implementation[B] 
} 

// Usage: 
import Evidence._ 
implicitly[Evidence[A]] 
implicitly[Evidence[B]] 

Jetzt gibt es keinen Namenskonflikt.

Wenn Sie eine tatsächliche ImplicitProvider haben müssen, können Sie diese stattdessen tun:

class ImplicitProvider[T] { ... } 

object ImplicitProviders { 
    implicit val aProvider = new ImplicitProvider[A] 
    implicit val bProvider = new ImplicitProvider[B] 

    implicit def ImplicitProvider2Evidence[T: ImplicitProvider]: Evidence[T] 
    = implicitly[ImplicitProvider[T]].evidence 
} 

// Usage 
import ImplicitProviders._ 
// ... 
+0

Aus irgendeinem Grund habe ich immer implicits Auflösung von Typ nur gedacht, gearbeitet, keine Namen zu berücksichtigen. Der eigentliche Zweck von 'ImplicitProvider' ist in meinem Fall die Bereitstellung von Circe' Encoder'/'Decoder' Instanzen für bestimmte Arten von Objekten. Diese Typen sind vorher nicht bekannt, daher können Sie in einem Objekt keine vorgefertigten Instanzen haben. Ich habe versucht, einen Mindeststandard für den Benutzer zu erreichen, ohne die einzelnen 'Encoder' /' Decoder' importieren oder referenzieren zu müssen. Danke für die implizite Konvertierung Tipp, es war das fehlende Glied. Es hat genau das getan, was gebraucht wurde. –

Verwandte Themen