【问题标题】:Scala Method on Generic Data Type通用数据类型的 Scala 方法
【发布时间】:2023-04-07 17:30:01
【问题描述】:

我正在尝试创建一个只接受 java.math.BigDecimal 或 Long 的泛型类。代码如下:

class myClass[T]()
{ 
    def display( x : T) = {
      println(x.doubleValue())
    }
}


val input = new java.math.BigDecimal(100)
// val input = 100L

val x = new myClass[java.math.BigDecimal]()
x.display(input)

显然我会有这个错误:ScalaFiddle.scala:22: error: value doubleValue is not a member of type parameter T.

我尝试了数小时的隐式转换、视图绑定和上下文绑定。至今没有结果。有什么办法可以强迫 Scala 相信我 T 有方法 .doubleValue()? (java.big.Decimal 和 Long 都有 .doubleValue() 方法,但它们不共享同一个超类)

【问题讨论】:

    标签: scala generics type-conversion implicit


    【解决方案1】:

    尝试结构类型绑定

    class myClass[T <: {def doubleValue(): Double}]
    

    或输入类

    trait HasDoubleValue[T] {
      def doubleValue(t: T): Double
    }
    object HasDoubleValue {
      implicit val long: HasDoubleValue[Long] = t => t.doubleValue
      implicit val bigDecimal: HasDoubleValue[BigDecimal] = t => t.doubleValue
    }
    
    implicit class DoubleValueOps[T: HasDoubleValue](x: T) {
      def doubleValue(): Double = implicitly[HasDoubleValue[T]].doubleValue(x)
    }
    
    class myClass[T: HasDoubleValue]
    

    【讨论】:

    • 数字有双值。然后只公开采用 Long 和 BigDec 的构造函数。
    • 您好 Dmytro,感谢您的回答。对于您的第一个解决方案,如果传入 Long,我将遇到此错误 - 错误:类型参数 [scala.this.Long] 不符合类 myClass 的类型参数边界 [T <: scala.this.anyref def doublevalue double java.lang.double scala long java anyref>
    • @bbbbz 试试val input1 = 100L val x1 = new myClass[java.lang.Long]() x1.display(input1)
    【解决方案2】:

    在 Dotty (Scala 3) 中,我们可以使用 union types,对于 example

    class myClass[T <: (Long | java.math.BigDecimal)]() { 
      def display(x: T) = 
        println(
          x match {
            case t: Long => t.doubleValue
            case t: java.math.BigDecimal => t.doubleValue
          }
        )
    }
    
    new myClass().display(new java.math.BigDecimal(100))   // OK
    new myClass().display(100L)                            // OK
    new myClass().display("100")                           // Error
    

    【讨论】:

      【解决方案3】:
      scala> class C private (n: Number) {
           | def this(i: Long) = this(i: Number)
           | def this(b: BigDecimal) = this(b: Number)
           | def d = n.doubleValue
           | }
      defined class C
      
      scala> new C(42L).d
      res0: Double = 42.0
      
      scala> new C(BigDecimal("123456789")).d
      res1: Double = 1.23456789E8
      

      或带有类型参数

      scala> class C[A <: Number] private (n: A) { def d = n.doubleValue ; def a = n } ; object C {
           | def apply(i: Long) = new C(i: Number) ; def apply(b: BigDecimal) = new C(b) }
      defined class C
      defined object C
      

      【讨论】:

      • 感谢您的解决方案!似乎只有当我将具有已定义数据类型的变量显式传递给 new C().d 时它才有效。就我而言,如果我将“x.doubleValue()”替换为“C(x).d”,Scala 将显示此错误:错误:使用替代方法重载方法构造函数 C:( b: BigDecimal)ScalaFiddle.this.C ( i: scala.this.Long)ScalaFiddle.this.C 不能应用于 (T)
      猜你喜欢
      • 2019-01-19
      • 2011-03-03
      • 1970-01-01
      • 1970-01-01
      • 2021-04-20
      • 2019-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多