Я рассматриваю рефакторинг немногих сигнатур методов, которые в настоящее время берут параметр типа List
или Set
из реальных классов-List[Foo]
- использовать повторенные параметры вместо этого: Foo*
.
Обновление: Следующее обоснование испорчено, пройти...
Это позволило бы мне использовать то же имя метода и перегружать его на основе типа параметра. Это не было возможным использованиемList
илиSet
, потому чтоList[Foo]
иList[Bar]
имейте тот же тип после стирания:List[Object]
.
В моем случае пересмотренные методы хорошо работают с scala.Seq[Foo]
это следует из повторного параметра. Я должен был бы изменить все вызовы и добавить аннотацию типа аргумента последовательности ко всем параметрам набора: baz.doStuffWith(foos:_*)
.
Учитывая, что переключение от параметра набора до повторного параметра семантически эквивалентно, это изменение оказывает некоторое влияние производительности, о котором я должен знать?
Ответ - то же для scala 2.7._ и 2.8?
] Когда Scala вызывает метод Scala varargs, метод получает объект, расширяющий Seq
. Когда вызов выполняется с помощью : _ *
, объект будет передан как * , без копирования. Вот примеры этого:
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)
Примечание
передается как WrappedArray
. Однако здесь не используется копирование элементов, и изменения в WrappedArray
будут отражены в Array
. Ваша причина для замены List [T] на T * ошибочна: Scala не допускает перегрузки, например
class Foo {{ 1}} {
def t1 (x: Int *) = println ("Ints")
def t1 (x: Strings *) = println ("Strings")
}
Это приведет к той же ошибке компилятора, что и при использовании здесь List [Int] / List [String].
Хотя это немного неуклюже, но вы могли бы использовать
class Foo
{
def t1 (x0: Int, x: Int *) = println ("Ints")
def t1 (x0: String, x: Strings *) = println ("Strings")
}
, но это требует особой обработки первого параметра по сравнению с остальными .
Гр. Сильвио
Проще говоря, все аргументы, которые соответствуют повторяющимся формальным параметрам, независимо от их происхождения, должны быть скопированы в последовательную коллекцию своего рода для представления методу. Детали того, какая именно последовательность используется, зависят от версии Scala и, возможно, от источника аргументов. Но независимо от этих деталей, это операция O (n), хотя стоимость одного элемента довольно низкая. Для самой последовательности будет выделено как минимум одно, а иногда и несколько экземпляров.
Рэндалл Шульц