Kosten von wiederholten Parametern
-
20-09-2019 - |
Frage
Ich halte Refactoring einige Methodensignaturen, die derzeit Parameter vom Typ List
oder Set
von konkreten Klassen --List[Foo]
-- Gebrauch nehmen wiederholten Parameter statt: Foo*
.
Aktualisieren : Nach Argumentation fehlerhaft ist, bewegen sich entlang ...
Dies würde erlauben Sie mir die gleiche Methode Namen zu verwenden und es Überlastung basierend auf dem Parameter-Typ. Das war nicht möglichList
oderSet
verwenden, weilList[Foo]
undList[Bar]
gleichen Typen nach dem Löschen haben.List[Object]
In meinem Fall der Überarbeitete Methoden funktionieren mit scala.Seq[Foo]
, dass den Ergebnissen aus den wiederholten Parametern. Ich möchte alle die Anrufungen sich ändern müssen, und fügen Sie ein Sequenz Argument Typanmerkung für alle Erfassungsparameter. baz.doStuffWith(foos:_*)
Da die von der Sammlung Parameter wiederholten Parameter Umschalten semantisch äquivalent ist, geht diese Änderung eine gewisse Auswirkungen auf die Leistung haben, dass ich bewusst sein sollten?
Ist die Antwort gleich für scala 2.7._ und 2.8?
Lösung
Wenn Scala ist eine Scala varargs Methode aufrufen, wird die Methode ein Objekt erhalten, die Seq
erstreckt. Wenn der Anruf mit : _*
gemacht wird, wird das Objekt als übergeben werden soll * , ohne sie zu kopieren. Hier sind einige Beispiele dafür:
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)
Hinweis
- Ein
Array
alsWrappedArray
geben. Es gibt kein Kopieren von Elementen beteiligt, aber, und Änderungen an denWrappedArray
werden imArray
reflektiert werden.
Andere Tipps
Ihr Grund für den Ersatz Liste [T] mit T * ist fehlerhaft: Scala wird nicht zulassen, eine Überlastung wie
class Foo
{
def t1(x : Int*) = println("Ints")
def t1(x : Strings*) = println("Strings")
}
Dieses im gleichen Compiler-Fehler führen wird, wie mit List [Int] / List [String] hier.
Obwohl ein bisschen ungeschickt könnten Sie
class Foo
{
def t1(x0 : Int,x : Int*) = println("Ints")
def t1(x0 : String,x : Strings*) = println("Strings")
}
aber das erfordert eine besondere Behandlung des ersten Parameters im Vergleich zu dem Rest.
Gr. Silvio
In der einfachstenen Form, alle Argumente, dass entspricht einen wiederholten formalen Parameter, unabhängig von ihrer Herkunft, muss auf das Verfahren zu einer sequentiellen Sammlung von irgendeiner Art für die Präsentation kopiert werden. Die Einzelheiten genau, welche Art von Sequenz verwendet wird, variieren mit Scala Version und möglicherweise mit der Quelle der Argumente. Aber unabhängig von diesen Details ist es eine O (n) -Operation, wenn die Kosten pro Stück ziemlich niedrig ist. Es wird für die Sequenz selbst eine und manchmal mehr wiesen Zuweisungen mindestens sein.
Randall Schulz