我考虑重构一些方法签名,这些方法签名目前采用类型List
或Set
类型的参数 - List[Foo]
- 来改为使用重复参数 :Foo*
。
更新:以下推理存在缺陷,请继续......
这将允许我使用相同的方法名称并根据参数类型重载它。使用List
或Set
无法做到这一点,因为List[Foo]
和List[Bar]
在删除后具有相同的类型:List[Object]
。
在我的情况下,重构的方法与重复参数产生的scala.Seq[Foo]
一起正常工作。我必须更改所有调用并将序列参数类型注释添加到所有集合参数:baz.doStuffWith(foos:_*)
。
鉴于从集合参数切换到重复参数在语义上是等效的,这个变化是否会产生一些我应该注意的性能影响?
scala 2.7._和2.8的答案是否相同?
答案 0 :(得分:4)
当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)
注意强>
Array
作为WrappedArray
传递。但是,不会复制所涉及的元素,WrappedArray
的更改将反映在Array
中。答案 1 :(得分:3)
你用T *替换List [T]的原因是有缺陷的:Scala不允许重载像
class Foo
{
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")
}
但这需要对第一个参数进行特殊处理,而不是其他参数。
的Gr。西尔维奥
答案 2 :(得分:0)
用最简单的术语来说,所有与重复形式参数相对应的参数,无论其来源如何,都必须复制到某种顺序集合中,以便呈现给方法。准确使用什么类型的序列的细节因Scala版本而异,并且可能与参数的来源有关。但无论这些细节如何,它都是O(n)操作,尽管每件物品的成本非常低。序列本身至少会有一个,有时甚至是更多的实例分配。
兰德尔舒尔茨