Question

Je considère refactorisation quelques signatures de méthode qui prennent actuellement paramètre de type List ou Set des classes concrètes --List[Foo]-- utiliser paramètres répétés à la place: Foo*.

  

Mise à jour : Après raisonnement est erroné, circulez ...   Cela me permettrait d'utiliser le même nom de la méthode et de surcharger en fonction du type de paramètre. Cela n'a pas été possible en utilisant List ou Set, parce List[Foo] et List[Bar] ont même type après l'effacement. List[Object]

Dans mon cas, les méthodes refactorisé fonctionnent très bien avec scala.Seq[Foo] qui résulte du paramètre répété. Je dois changer toutes les invocations et ajouter un argument séquence annotation de type à tous les paramètres de collecte. baz.doStuffWith(foos:_*)

Étant donné que le passage du paramètre de collection au paramètre répété est sémantiquement équivalent, ce que ce changement ont un certain impact sur les performances que je devrais être au courant?

La réponse est de même pour scala 2.7._ et 2.8?

Était-ce utile?

La solution

Quand Scala appelle une méthode Scala varargs, la méthode reçoit un objet qui étend Seq. Lorsque l'appel est fait avec : _*, l'objet sera adopté tel quel * , sans copier. Voici les exemples:

scala> object T {
     |   class X(val self: List[Int]) extends SeqProxy[Int]  {
     |     private val serial = X.newSerial
     |     override def toString = serial.toString+":"+super.toString
     |   }
     |   object X {
     |     def apply(l: List[Int]) = new X(l)
     |     private var serial = 0
     |     def newSerial = {
     |       serial += 1
     |       serial
     |     }
     |   }
     | }
defined module T

scala> new T.X(List(1,2,3))
res0: T.X = 1:List(1, 2, 3)

scala> new T.X(List(1,2,3))
res1: T.X = 2:List(1, 2, 3)

scala> def f(xs: Int*) = xs.toString
f: (Int*)String

scala> f(res0: _*)
res3: String = 1:List(1, 2, 3)

scala> f(res1: _*)
res4: String = 2:List(1, 2, 3)

scala> def f(xs: Int*): Seq[Int] = xs
f: (Int*)Seq[Int]

scala> def f(xs: Int*) = xs match {
     |   case ys: List[_] => println("List")
     |   case _ => println("Something else")
     | }
f: (Int*)Unit

scala> f(List(1,2,3): _*)
List

scala> f(res0: _*)
Something else

scala> import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.ArrayBuffer

scala> def f(xs: Int*) = xs match {
     |   case ys: List[_] => println("List")
     |   case zs: ArrayBuffer[_] => zs.asInstanceOf[ArrayBuffer[Int]] += 4; println("Array Buffer")
     |   case _ => println("Something else")
     | }
f: (Int*)Unit

scala> val ab = new ArrayBuffer[Int]()
ab: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()

scala> ab + 1
res11: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1)

scala> ab + 2
res12: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 2)

scala> ab + 3
res13: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 2, 3)

scala> f(ab: _*)
Array Buffer

scala> ab
res15: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4)

Remarque

  • Un Array est passé comme un WrappedArray. Il n'y a pas de copie d'éléments impliqués, cependant, et les changements au WrappedArray seront pris en compte dans le Array.

Autres conseils

Votre raison pour le remplacement Liste [T] avec T * est défectueux: Scala ne permettra pas à une surcharge comme

class Foo
{
   def t1(x : Int*) = println("Ints")
   def t1(x : Strings*) = println("Strings")
}

Cela se traduira par la même erreur du compilateur en utilisant la liste [Int] / Liste [chaîne] ici.

Bien qu'un peu maladroit, vous pouvez utiliser

class Foo
{
   def t1(x0 : Int,x : Int*) = println("Ints")
   def t1(x0 : String,x : Strings*) = println("Strings")
}

mais qui nécessite un traitement spécial du premier paramètre par rapport au reste.

Gr. Silvio

Dans les termes les plus simples, tous les arguments qui correspondent à un des paramètres formels répétées, quelle que soit leur origine, doivent être copiés dans une collection séquentielle de quelque sorte pour la présentation à la méthode. Les détails de exactement ce type de séquence est utilisée varient avec la version Scala et peut-être à la source des arguments. Mais indépendamment de ces détails, il est un O (n) exploitation, bien que le coût par article est assez faible. Il y aura au moins un et parfois plusieurs allocations d'instance pour la séquence elle-même.

Randall Schulz

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top