给出以下代码:
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:错误:类型不匹配;
发现:Field.this.T
必需:字符串
def sum:T = data(0)+ data(1)
^
也就是说,它期望数据(1)为String
。
我不明白为什么......(scala 2.8.1)
非常感谢您的解释!
答案 0 :(得分:17)
由于T
不支持添加操作,因此编译器假定+
是字符串连接操作。我在REPL尝试的以下行表示如下:
scala> implicitly[Any => {def +(s: String): String}]
res16: (Any) => AnyRef{def +(s: String): String} = <function1>
您可以做的是要求T
定义Semigroup
代数。 (如果类型支持关联追加操作,则类型为半群。)
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] = $anon$1@d1fd51
scala> f.sum
res12: Int = 5
我用类型参数替换了抽象类型,因为我不知道如何在抽象类型上放置上下文绑定。我还将数据类型从List[A]
更改为IndexedSeq[A]
,因为名称表示索引序列比列表更适合索引访问(这是您在sum
方法中执行的操作)。最后,|+|
是半群追加操作。对于数字类型,它将执行添加。对于序列,连接等。
答案 1 :(得分:4)
作为@ missingfactor答案的补充,虽然原则上我非常赞成Semigroup
,标准库中有一个特征Numeric
也可以这样做。对于内容为Numeric
的集合(其中元素的类型存在“Numeric
结构”),您只需调用collection.sum
(如果您想要将所有元素相加而不是两个第一个)。
我更喜欢Semigroup
有两个原因。第一Numeric
远远超过此处所需要的,第二,Numeric
结构的确切属性尚不清楚。另一方面,即使不熟悉基本代数的人也会对数字的含义有一个合理的理解。
因此,如果您害怕scalaz和/或半群,则可以将Semigroup
替换为Numeric
,将|+|
替换为+
。您必须import Numeric.Implicits._
才能+
可用。
答案 2 :(得分:3)
编译器不知道如何在类型+
中调用T
,因为它对T
一无所知。编译这个+
的唯一解决方案是一个pimped字符串连接(通过隐式Predef.any2stringadd
),它期望一个字符串作为第二个参数 - 因此你得到的错误。
答案 3 :(得分: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(_, _)))
}