2015-06-14 2 views
2

Рассмотрим следующее определение сложить все элементы в гнездовой Iterable структуре Ints:Массив массивов, как Iterable из итерируемыми

def add(xss : Iterable[Iterable[Int]]) : Int = xss.map(_.sum).sum 

Однако, оценивая следующее выражение дает ошибку типа:

scala> add(Array(Array(1,2,3))) 
    <console>:9: error: type mismatch; 
    found : Array[Array[Int]] 
    required: Iterable[Iterable[Int]] 
       add(Array(Array(1,2,3))) 
         ^

Функция работает, как и ожидалось, с другими Iterables (например, списками). Как я могу избежать этой ошибки? В чем причина? Угадайте, что это связано с тем, что Arrays является родным с Java, но в этом случае не знает подробностей.

Thanks

+1

Является ли этот метод должен принимать 'Iterable [Iterable [Int]]' вместо этого? Потому что это компилируется для меня. –

+0

Вы правы. Я сделал ошибку, копируя код. Теперь это исправлено. Благодарю. Ошибка сохраняется, как указано. – pepeStck

ответ

3

Это не работает, потому что Scala нужно было бы использовать 2 неявное преобразование в ряд, чтобы перейти от Array[Array[Int]] к Iterable[Iterable[Int]], что это (целенаправленно) не делает.

Вы можете указать внешней Array тип «s:

scala> add(Array[Iterable[Int]](Array(1,2,3))) 
res4: Int = 6 

или преобразовать его элементы в Iterable[Int] (в обход неявное преобразование):

scala> add(Array(Array(1,2,3)).map(_.toIterable)) 
res5: Int = 6 

Проблема исходит из факт, что Scala's Array[T] является просто представлением для Java T[]. Что делает Array[T] вести себя как обычная коллекция Scala - это неявное преобразование в Predef.

От Array's documentation:

Two implicit conversions exist in scala.Predef that are frequently applied to arrays: a conversion to mutable.ArrayOps and a conversion to mutable.WrappedArray (a subtype of scala.collection.Seq). Both types make available many of the standard operations found in the Scala collections API. The conversion to ArrayOps is temporary, as all operations defined on ArrayOps return an Array, while the conversion to WrappedArray is permanent as all operations return a WrappedArray.

The conversion to ArrayOps takes priority over the conversion to WrappedArray.

+0

Спасибо. Какова будет проблема с непосредственным выполнением 2 неявных преобразований? – pepeStck

+1

@ppgllrd: Я не мог найти никакой официальной причины для этого, но я предполагаю, что это резко увеличит количество возможных преобразований и просто не стоит этого. Плюс (простое) неявное преобразование уже может затруднить понимание фрагмента кода, я действительно не хочу пытаться понять «вложенные» неявные преобразования. – Marth

+0

Еще раз спасибо.Эти неравномерности массивов по сравнению с другими структурами данных Scala являются одной из вещей, которые мне меньше нравятся в этом замечательном языке программирования. Цена за использование эффективных массивов от подчеркивания JVM. – pepeStck

-1

Ваша интуиция верна. См Array сигнатуру типа:

final class Array[T] extends java.io.Serializable with java.lang.Cloneable 

контраст, который с Seq типа подписи:

trait Seq[+A] extends Iterable[A] with collection.Seq[A] ... 

Как вы можете видеть Array не относится к Iterable[A] признака.

Вы можете исправить это с помощью вызова toIterable на экземпляре:

scala> add(Array(Array(1,2,3).toIterable).toIterable) 
res1: Int = 6 
+1

Спасибо, Гэвин, но то, что интригует меня, это то, что если я удалю вложенность, массивы можно использовать как Iterables. Например, 'def add2 (xs: Iterable [Int]) = xs.sum' корректно работает с' add2 (Array (1,2,3)) '. – pepeStck

Смежные вопросы