【问题标题】:Scala: Function returning an unknown typeScala:返回未知类型的函数
【发布时间】:2015-05-12 03:55:44
【问题描述】:

如果我想创建一个 add 方法来添加两种不同类型的值,例如:

add[T,S](op1: T, op2: S): ? = ...

我能想到的最值得注意的例子是基本数字类型。如果我添加一个 Byte 和一个 Int,那么它将返回一个 Int。如果添加两个字节,它可能会返回一个 Int,具体取决于字节的 -127 到 128 限制是否被打破。

如果我想创建具有相同特征的类,我希望它也能这样做。

一种可能的解决方案是让类扩展相同的特征或类。但是对于 Scala 原始类型的示例,这并不适用,因为 Int、Double、Float、Byte 除了 Any 之外不共享一个共同的祖先。

我还查看了 Numeric[T] 特征,但在添加不同的原始类型时这似乎没有帮助。

谢谢 启

【问题讨论】:

    标签: scala types numbers


    【解决方案1】:

    这是某种联合类型类的主要示例。

    首先定义一个类似于Numeric[T] 的东西,但为了可添加性:

    trait Addable[T, S] {
      type Result
      def add(x: T, y: S): Result
    }
    

    现在,定义您的 add 函数:

    def add[T,S](op1: T, op2: S)(implicit op: Addable[T, S]): op.Result =
      op.add(op1, op2)
    

    剩下要做的就是为Addable创建隐式实例:

    // Put them in the companion object, so the implicits are available
    // without explicit import
    object Addable {
      // Make any numeric addable
      implicit def numericAddable[T : Numeric]: Addable[T, T] = {
        new Addable[T, T] {
          type Result = T
          def add(x: T, y: T): T = {
            val op = implicitly[Numeric[T]]
            op.plus(x, y)
          }
        }
      }
    }
    

    但您现在也可以定义自己的类并定义(非对称)添加能力:

    case class A(x: Int)
    case class B(x: Int)
    case class C(x: Int)
    
    implicit object AddABC extends Addable[A,B] {
      type Result = C
      def add(x: A, y: B): C = C(x.x + y.x)
    }
    

    这将允许你写:

    add(A(1), B(2))
    

    但是,其中任何一个都会在编译时失败:

    add(A(1), A(2))
    add(B(1), A(2))
    add(B(1), B(2))
    

    不幸的是,这不适用于弱一致性数字类型:

    add(1, 1) // compiles
    add(1.0, 1.0) // compiles
    add(1, 1.0) // fails to compile
    

    another post 来看,除了手动定义案例(当然还有一些辅助方法)之外,没有其他方法可以实现这一点。

    【讨论】:

    • 所以我今天刚刚研究了您的解决方案以及您链接到的解决方案。学习一些新东西,我第一次知道一个字节 + 字节无论如何都会返回一个 int !但是有什么理由不依赖于字节的值吗?当您可以通过将字节保持在其数字范围内来潜在地节省空间时,这似乎有点低效。如果我想在我的代码中进行以下操作,我一直在研究 Scalas "Either" 类型。在这种情况下,我会在添加包装类时返回一个 Either 然后模式匹配。只是想知道是否有什么特别的理由不这样做。
    • 在 Scala 中,byte + byte 返回一个 int,主要是因为 JVM(和 Java)就是这样做的。我不知道为什么 Java 是这样设计的。
    猜你喜欢
    • 1970-01-01
    • 2016-06-29
    • 1970-01-01
    • 2014-05-29
    • 2011-02-14
    • 1970-01-01
    • 2021-02-11
    • 1970-01-01
    • 2018-02-23
    相关资源
    最近更新 更多