2011-08-25 55 views
3

考慮下面的代碼:爲什麼要尋找字符串?

abstract class Field { 
    type T 
    val data: List[T] 
    def sum: T = data(0) + data(1) 
} 

我上最後一行的錯誤 - def sum: T = data(0) + data(1)

types2.scala:6: error: type mismatch;

found : Field.this.T

required: String

def sum: T = data(0) + data(1)

    ^

也就是說,它預計數據(1)是一個String。 我不明白爲什麼...(斯卡拉2.8.1)

您的解釋將不勝感激!

回答

17

由於T不支持添加操作,編譯器假定+是一個字符串連接操作。下面的行我在REPL試用表明這樣:

scala> implicitly[Any => {def +(s: String): String}] 
res16: (Any) => AnyRef{def +(s: String): String} = <function1> 

你可以做的是要求T定義一個Semigroup代數。 (A型爲半羣,如果它支持關聯追加操作。)

scala> import scalaz._ 
import scalaz._ 

scala> import Scalaz._ 
import Scalaz._ 

scala> abstract class Field[A : Semigroup] { 
    | val data: IndexedSeq[A] 
    | def sum: A = data(0) |+| data(1) 
    | } 
defined class Field 

scala> val f = new Field[Int] { 
    | val data = IndexedSeq(2, 3, 4) 
    | } 
f: Field[Int] = [email protected] 

scala> f.sum 
res12: Int = 5 

我取代抽象類型的類型參數,只是因爲我不知道如何把綁定在一個抽象類型的上下文。我還將數據類型從List[A]更改爲IndexedSeq[A],因爲名稱表示索引序列比列表更適合索引訪問(這是您在sum方法中執行的操作)。最後,|+|是半羣追加操作。對於數字類型,它將執行加法。對於序列,連接等

+0

我該如何使它與Ints,浮動和字符串一起工作? –

+0

@CodeChords man:檢查編輯。 – missingfaktor

3

編譯器不知道如何在T類型中調用+,因爲它對T一無所知。編譯此+的唯一解決方案是一個字符串連接(通過隱含的Predef.any2stringadd),它需要一個字符串作爲第二個參數 - 因此會出現錯誤。

4

作爲@ missingfactor答案的補充,雖然原則上我會非常青睞Semigroup,但標準庫中會有一個特性Numeric,它可以做到這一點。對於內容爲Numeric(其中「元素類型」存在「Numeric結構」)的集合,您可以簡單地調用collection.sum(如果要總結所有元素而不是兩個第一個元素)。

我更喜歡Semigroup有兩個原因。第一個Numeric比這裏需要的要多得多,第二,Numeric結構的確切屬性有什麼不清楚。另一方面,即使是不熟悉基本代數的人也會對數字的含義有一個合理的理解。

所以,如果你是怕scalaz和/或半羣,你可以用Numeric|+|+取代Semigroup。您必須import Numeric.Implicits._以便+可用。

+0

我改變了我的答案,使用'Semigroup'而不是'Monoid'作爲關聯追加操作。 – missingfaktor

+0

好的,我也改變了我對Semigroup的回答,那樣會更容易混淆。 –

+0

+1,現在看起來不錯。如果OP不想拉斯卡拉,「Numeric」或許是他可以選擇的最佳解決方案。 – missingfaktor

0

經過很多玩這個,我想出了一個非常簡單的解決方案。 以下是完整的程序

package manytypes 

abstract class Field { 
    type T 
    val data: List[T] 
    def add (a: T, b: T): T 
} 

abstract class FieldInt extends Field { 
    type T = Int 
    def add (a: T, b: T): T = a + b 
} 

abstract class FieldDouble extends Field { 
    type T = Double 
    def add (a: T, b: T): T = a + b 
} 

abstract class FieldString extends Field { 
    type T = String 
    def add (a: T, b: T): T = a + b 
} 

object A extends App { 

    val ints: Field = new FieldInt { val data = List(1, 2, 3)} 
    val doubles: Field = new FieldDouble { val data = List(1.2, 2.3, 3.4) } 
    val strings: Field = new FieldString { val data = List("hello ", "this is ", "a list ")} 

    val fields: List[Field] = List(ints, doubles, strings) 

    for (field <- fields) println(field.data.reduceLeft(field.add(_, _))) 
} 
相關問題