Стоимость использования повторных параметров

Я рассматриваю рефакторинг немногих сигнатур методов, которые в настоящее время берут параметр типа List или Set из реальных классов-List[Foo]- использовать повторенные параметры вместо этого: Foo*.

Обновление: Следующее обоснование испорчено, пройти...
Это позволило бы мне использовать то же имя метода и перегружать его на основе типа параметра. Это не было возможным использованием List или Set, потому что List[Foo] и List[Bar] имейте тот же тип после стирания: List[Object].

В моем случае пересмотренные методы хорошо работают с scala.Seq[Foo] это следует из повторного параметра. Я должен был бы изменить все вызовы и добавить аннотацию типа аргумента последовательности ко всем параметрам набора: baz.doStuffWith(foos:_*).

Учитывая, что переключение от параметра набора до повторного параметра семантически эквивалентно, это изменение оказывает некоторое влияние производительности, о котором я должен знать?

Ответ - то же для scala 2.7._ и 2.8?

5
задан Palimondo 18 March 2010 в 01:59
поделиться

3 ответа

] Когда 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 .
4
ответ дан 14 December 2019 в 08:48
поделиться

Ваша причина для замены 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") 
} 
 

, но это требует особой обработки первого параметра по сравнению с остальными .

Гр. Сильвио

3
ответ дан 14 December 2019 в 08:48
поделиться

Проще говоря, все аргументы, которые соответствуют повторяющимся формальным параметрам, независимо от их происхождения, должны быть скопированы в последовательную коллекцию своего рода для представления методу. Детали того, какая именно последовательность используется, зависят от версии Scala и, возможно, от источника аргументов. Но независимо от этих деталей, это операция O (n), хотя стоимость одного элемента довольно низкая. Для самой последовательности будет выделено как минимум одно, а иногда и несколько экземпляров.

Рэндалл Шульц

0
ответ дан 14 December 2019 в 08:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: