2015-04-01 10 views
2

дал следующую подпись для параметризованных методаScala параметризованных типа на foldLeft

def double[A <: Byte](in:List[A]): List[A] = { 
    //double the values of the list using foldLeft 
    //for ex. something like: 
    in.foldLeft(List[A]())((r,c) => (2*c) :: r).reverse 
    //but it doesn't work! so.. 
} 

я пытался получить следующее, прежде чем приступать параметризированный напечатанное foldLeft

def plainDouble[Int](in:List[Int]): List[Int] = { 
    in.foldLeft(List[Int]())((r:List[Int], c:Int) => { 
    var k = 2*c 
    println("r is ["+r+"], c is ["+c+"]") 
    //want to prepend to list r 
    // k :: r 
    r 
}) 
} 

однако, это приводит к следующей ошибке :

$scala fold_ex.scala 
error: overloaded method value * with alternatives: 
(x: Double)Double <and> 
(x: Float)Float <and> 
(x: Long)Long <and> 
(x: scala.Int)scala.Int <and> 
(x: Char)scala.Int <and> 
(x: Short)scala.Int <and> 
(x: Byte)scala.Int 
cannot be applied to (Int(in method plainDouble)) 
val k = 2*c 
     ^
one error found 

если я изменил подпись def на последующие ING:

def plainDouble(in:List[Int]): List[Int] = { ...} 

работы и выход для:

val in = List(1,2,3,4,5) 
println("in "+ in + " plainDouble ["+plainDouble(in)+"]") 

является

in List(1, 2, 3, 4, 5) plainDouble [List(2, 4, 6, 8, 10)] 

извинения, если я что-то очень очевидное отсутствует.

ответ

1

@DNA верна в том, что plainDouble[Int] объявляет параметр типа с именем Int, который не имеет ничего общего с фактическим типом. Таким образом, ваша попытка сделать его неэквивалентным на самом деле все еще носит общий характер, но не так очевидна.

Но как насчет оригинальной проблемы?

scala> def double[A <: Byte](in: List[A]): List[A] = in.foldLeft(List.empty[A])((r,c) => (2*c) :: r) 
<console>:15: error: type mismatch; 
found : x$1.type (with underlying type Int) 
required: A 
     def double[A <: Byte](in: List[A]): List[A] = in.foldLeft(List.empty[A])((r,c) => (2*c) :: r).reverse 
                          ^

Проблема здесь состоит в том, что 2 * c является Int, а не A. Метод *(byte: Byte) на Int возвращает еще Int. Отсюда сообщение (with underlying type Int). Обратите внимание, что если вы приводите к A, она составляет:

def double[A <: Byte](in: List[A]): List[A] = 
    in.foldLeft(List.empty[A])((r,c) => (2*c).toByte.asInstanceOf[A] :: r).reverse 

Обратите внимание, как я должен был назвать toByte перед заливкой в ​​A. Это не совсем яркий пример дженериков на работе, но дело в том, что несовместимые типы возвращаемых данных вызывают ошибку.

заметить также, как это не происходит, если вы удалите 2 *:

def double[A <: Byte](in: List[A]): List[A] = 
    in.foldLeft(List.empty[A])((r,c) => c :: r).reverse 

Edit:

Вы могли бы рассмотреть вопрос об использовании Numeric признака для дженериков, как это.

import scala.math.Numeric.Implicits._ 

def double[A: Numeric](in: List[A])(implicit i2a: Int => A): List[A] = 
    in.map(_ * 2) 

Это зависит от неявного Numeric[A] быть доступным для вашего числового типа (которые существуют в scala.math.Numeric объекта, для почти любого числового типа вы хотите). Он также полагается на неявное преобразование, доступное от Int до A, так что мы можем написать a * 2. Мы можем отказаться от этого ограничения, используя вместо этого +:

def double[A: Numeric](in: List[A]): List[A] = in.map(a => a + a) 
+0

спасибо «DNA» и @mz, однако, 'def doubleBound [A <: Byte] (in: List [A]): ​​List [A] = in.foldLeft (List.empty [A]) ((r, c) => (2 * c) .toByte.asInstanceOf [A] :: r) .реверсия val in = Список (1,2,3,4,5) println ("in" + in + "doubleBound ["+ doubleBound (in) +"] ")' все еще жалуется на 'error: аргументы inferred type [Int] не соответствуют методу параметра метода doubleBound [A <: Byte]' – cogitate

+0

@cogitate «Int» не является 'Byte'. 'A' не может представлять' Int', если 'A' ограничено выше' Byte'. –

+0

Попробуйте использовать фактический список 'Byte's:' List (1, 2, 3). map (_. toByte) ' –

3

Проблема является своего рода имя затенения:

def plainDouble[Int](in:List[Int]): List[Int] = { 
       ^^^ 
     // this is a type parameter called "Int" 

Вы объявляете переменную типа под названием Int, в то же время пытается использовать конкретный тип Int, и это вызывает путаницу. Если вы удалите переменную типа (поскольку она фактически не используется) или переименуйте ее, например, в I, тогда код компилируется.

+0

Да, поскольку я тоже нашел. однако, как бы вы сделали параметризованный тип работы? – cogitate

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

  • Нет связанных вопросов^_^