2012-06-20 6 views
1

Я немного прочитал о Manifests и методах избегания стирания, необходимых, чтобы позволить Scala делать что-то вроде «нового массива [Array [T]]», но я немного озадачен этим ...Scala параметризация моего массива принимает строку?

У меня есть метод, похожий на таблицу, состоящую из нескольких строк в массиве, таком как электронная таблица. Например представить 2D массив так:

11, 5, 4 
8, 3, 7 
2, 1, 4 

Я написал метод, который суммирует столбцы этого массива и выплевывает 1D массив, как [21, 9, 15]

Я хочу genericize это больше, чем просто инты (например, Doubles или Floats), и когда я добавляю параметр и манифест, я получаю ошибку компиляции.

Вот код

def sumGrid[T](grid: Array[Array[T]])(implicit m: ClassManifest[T]): Array[T] = { 

    val sum = new Array[T](grid(0).size) 

    for(i <- 0 until grid.size) { 
    for(j <- 0 until grid(0).size) { 
     sum(j) = sum(j) + grid(i)(j) 
    } 
    } 
    sum 
} 

Вот ошибка компиляции:

[ERROR] ...scala/euler/GridOperations.scala:126: error: type mismatch; 
[INFO] found : T 
[INFO] required: String 
[INFO]   sum(j) = sum(j) + grid(i)(j) 
[INFO]        ^
[ERROR] one error found 

Что здесь происходит? Почему String «требуется»?

+3

Обратите внимание, что в этом случае вы можете обойти этот вопрос, написав определение функции sumGrid [T: Числовые] (сетка: Array [Array [T]]) = grid.transpose.map (. _ Сумма) '. –

ответ

6

Поскольку вы используете оператор +, который всегда определен для строк. Любой тип может быть преобразован в String (toString всегда определен), и таким образом он будет работать для любого типа T.

Но вы можете добавить некоторые ограничения на T, чтобы убедиться, что это соответствует арифметической операции. Например, вы можете использовать implicits, чтобы получить Numeric объектов, определяющих добавление к типу T:

def sumGrid[T](grid: Array[Array[T]]) 
(implicit m: ClassManifest[T], num: Numeric[T]): Array[T] = { 

    val sum = new Array[T](grid(0).size) 

    for(i <- 0 until grid.size) { 
    for(j <- 0 until grid(0).size) { 
     sum(j) = num.plus(sum(j), grid(i)(j)) 
    } 
    } 
    sum 
} 
+0

Спасибо, парадигматично! Это сделал трюк. – user311121

0

Вы обработали Array части, но T не имеет ограничивающего, которые говорят, что есть метод +. Из-за этого Scala думает, что вы добавляете строки - он будет автоматически конвертировать любой тип в String, когда вы добавите его другому String. Поэтому он автоматически конвертировал sum(j) в String, и теперь ожидает, что grid(i)(j) будет другим String, после чего он откажется и потерпит неудачу.

Вы можете обрабатывать вещи около T, являясь цифровым способом, аналогичным ClassManifest. Здесь:

// I'm using the "context bound" notation, to make the declaration shorter and 
// more obvious on what I'm saying about T 
def sumGrid[T : ClassManifest : Numeric](grid: Array[Array[T]]): Array[T] = { 
    // the following line, plus the Numeric bound, makes T usable as a number 
    import scala.math.Numeric.Implicits._ 

    val sum = new Array[T](grid(0).size) 

    for(i <- 0 until grid.size) { 
    for(j <- 0 until grid(0).size) { 
     sum(j) = sum(j) + grid(i)(j) 
    } 
    } 
    sum 
} 
Смежные вопросы