【问题标题】:Why is it looking for String?为什么要寻找字符串?
【发布时间】:2011-11-03 12:27:54
【问题描述】:

给定以下代码:

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

必需:字符串

定义总和:T = 数据(0) + 数据(1)

                     ^

也就是说,它期望 data(1) 是 String。 我不明白为什么......(scala 2.8.1)

您的解释将不胜感激!

【问题讨论】:

    标签: scala


    【解决方案1】:

    由于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 方法中所做的)。最后,|+| 是半群追加操作。对于数字类型,它将执行加法。对于序列、连接等。

    【讨论】:

      【解决方案2】:

      作为对@missingfactor 答案的补充,虽然原则上我非常喜欢Semigroup,但标准库中有一个特征Numeric 可以做到这一点。对于内容为Numeric 的集合(其中元素类型存在“Numeric 结构”),您可以简单地调用collection.sum(如果您想对所有元素求和,而不是前两个元素)。

      我更喜欢Semigroup 有两个原因。首先Numeric 比这里需要的要多得多,其次,Numeric 结构的确切属性是什么尚不清楚。另一方面,即使是不熟悉基本代数的人也会对数字的含义有一个合理的理解。

      因此,如果您害怕 scalaz 和/或半群,您可以将 Semigroup 替换为 Numeric 并将 |+| 替换为 +。您必须import Numeric.Implicits._ 以便+ 可用。

      【讨论】:

      • 我将答案更改为使用Semigroup 而不是Monoid,因为这里只需要关联附加操作。
      • 好的,我也将我的答案更改为 Semigroup,这样就不会那么混乱了。
      • +1,现在看起来不错。如果 OP 不想加入 Scalaz,Numeric 或许是他可以寻求的最佳解决方案。
      【解决方案3】:

      编译器不知道如何在您的类型T 中调用+,因为它对T 一无所知。编译这个+ 的唯一解决方案是一个拉皮条的字符串连接(通过隐式Predef.any2stringadd),它需要一个字符串作为第二个参数——因此你得到的错误。

      【讨论】:

        【解决方案4】:

        在玩了很多之后,我想出了一个非常简单的解决方案。 这是完整的程序

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

        【讨论】:

          猜你喜欢
          • 2016-03-11
          • 1970-01-01
          • 2015-05-08
          • 2017-03-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-30
          • 2012-01-30
          相关资源
          最近更新 更多