为什么要寻找String?

时间:2011-08-25 09:28:47

标签: scala

给出以下代码:

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)

非常感谢您的解释!

4 个答案:

答案 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(_, _)))
}