簡體   English   中英

foldLeft上的scala參數化類型

[英]scala parameterized type on 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的簽名更改為以下內容:

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)]

抱歉,如果我錯過了一些非常明顯的內容。

問題是一種名稱隱藏:

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

您在聲明一個名為Int的類型變量的同時,還嘗試使用具體類型Int ,這會引起混亂。 例如,如果刪除類型變量(因為它實際上並未使用)或將其重命名為I ,則代碼將編譯。

@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 Int上的*(byte: Byte)方法返回另一個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

注意在轉換為A之前我還必須調用toByte 這並不是泛型在工作中的一個光輝的例子,但重點是不兼容的返回類型正在導致錯誤。

還要注意,如果刪除2 *它不會發生:

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

編輯:

您可能會考慮對此類泛型使用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對象中存在該scala.math.Numeric ,幾乎是您想要的任何數字類型)。 它還依賴於從IntA的隱式轉換,以便我們可以編寫a * 2 我們可以使用+代替此約束:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM