2011-08-25 56 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(_, _))) 
} 
相关问题