2017-05-16 3 views
0

ich eine einfache implizite Funktion schrieb: eine Version von mkString(), die funktioniert identisch, aber wirft einen Fehler, wenn der Separator gefunden wird in einem der Argumente verbunden werden. Ich möchte es alle sequenz wie die Dinge funktionieren über, so erklärte ich es wie folgt:Scala 2.10 implizite Funktion über TraversableOnce sollte ein Array akzeptieren, aber nicht

object SafeMkString { 
    implicit class SafeMkStringHelper[T](values: TraversableOnce[T]) { 
    def safeMkString(sep: String) = { 
     values.map { v => 
     val asStr = v.toString 
     if (asStr.contains(sep)) 
      throw new IllegalArgumentException("Value %s in %s contains separator %s" format 
      (asStr, values, sep)) 
     else 
      asStr 
     }.mkString(sep) 
    } 
    } 
} 

Dies funktioniert für die meisten Objekte in Ordnung, aber nicht in Scala 2.10 mit etwas vom Typ Array[String]. Dies liegt daran, dass Arrays in Scala einfach Aliase von Java-Arrays sind und nicht von TraversableOnce erben. Allerdings gibt es eine implizite Konvertierung Array-WrappedArray die tut vererben TraversableOnce. Gibt es eine Regel in Scala, die eine implizite Umwandlung von A -> B und dann von B -> C nicht zulässt? Gibt es irgendeine Weise, die ich diese Arbeit anderen bekommen können als manuell eine andere implizite Klasse erstellen, die explizit safeMkString von Array[T] gilt?

Antwort

3

In Antwort auf Ihre erste Frage, ist dies aus Programming in Scala (1st Edition), Kapitel 21:

One-at-a-time-Regel: Nur eine impliziten versucht. Der Compiler wird niemals x + y umschreiben, um convert1 (convert2 (x)) + y. Dies würde dazu führen, dass sich die Kompilierungszeiten bei fehlerhaftem Code drastisch erhöhen, und es würde den Unterschied zwischen dem, was der Programmierer schreibt, und dem, was das Programm tatsächlich tut, erhöhen. Aus Gründen der Übersichtlichkeit fügt der Compiler keine weiteren impliziten Konvertierungen ein, wenn er bereits versucht, einen anderen implizit zu testen. Es ist jedoch möglich, diese Einschränkung zu umgehen, indem man implizite Parameter impliziert, die später in diesem Kapitel beschrieben werden.

+0

Doh, das ist wirklich ein Fall von RTFM. –

2

von @jwvh Antwort Inspired (vor allem die letzte Zeile des Zitats), kam ich mit dem Follow-up:

implicit class CanBeTraversable[A, T](a: A)(implicit ev: A => TraversableOnce[T]){ 
    def safeMkString(sep: String) = { 
    val values = ev(a) 
    ... //put here the body of your method 
} 

Was sie tut, ist A eine implizite Konvertierung von jeder Art geben, die eine hat implizite Umwandlung in TraversableOnce[T] für einige T. Dies funktioniert für List seit =:= : List[T] => List[T] ist eine implizite Konvertierung (auch, da Function1 ist kovariant in seinem zweiten Parameter, Function1[List[T], List[T]] <: Function1[List[T], TraversableOnce[T]]). Es funktioniert auch für Array, da es die implizite Konvertierung zu WrappedArray hat.