如何规避不变性?例如。将Array [T]传递给func(Array [U]),其中T <:U

时间:2013-12-19 09:51:17

标签: scala variance

我正在使用现有的java库练习scala。将 Array [T] 传递给 func(Array [U]),其中 T&lt;:U 是很常见的。例如:

爪哇:

public class Quick { ...
    public static void sort(Comparable[] a) { ... }
}

public class Edge implements Comparable<Edge> { ... }

public class EdgeWeightedGraph { ...
    public Iterable<Edge> edges() { ... }
}

Scala的:

class Kruskal(private val G: EdgeWeightedGraph) {
    init()
    private def init() = {
        val es = G.edges().asScala.toArray
        /* **Error** Type mismatch, 
         *           expected: Array[Comparable[_]], 
         *           actual: Array[Edge]
         */
        Quick.sort(es)  
        ...
    }
}

我相信这是因为数组是不变的。这是我试图绕过这一点,但它看起来很丑陋而且效率低下:

val es = G.edges().asScala.map(_.asInstanceOf[Comparable[_]]).toArray)
Quick.sort(es)

我该如何以更好的方式做到这一点?

1 个答案:

答案 0 :(得分:2)

数组是不变的,因为它们是可变的。如果它们不是不变的,你可以做类似

的事情
class Fruit
class Apple extends Fruit
class Orange extends Fruit

val apples:Array[Apple] =  Array(new Apple())
val fruits:Array[Fruit] = apples
fruits.update(0,new Orange)

val apple:Apple = apples(0) //<= epic fail I now have an orange as an apple ?

我能想到的唯一方法是集合复制到等效的不可变集合(collection.immutable.Seq的子类型)

class Fruit
class Apple extends Fruit
class Orange extends Fruit

val apples:Array[Apple] =  Array(new Apple())
val fruits:collection.immutable.Seq[Fruit]=apples.toList // or apples.toIndexedSeq

然后得到一个不可变的集合,你可以得到方差

在您的具体示例中,您可以更改

val es = G.edges().asScala.toArray

val es = G.edges().asScala.toIndexedSeq

但是你必须让QuickSort签名接受我猜的IndexedSeq。没有更多的代码就很难说清楚后果......