基于类型的泛型函数根据类型对数字求和 [英] generic type-based function to sum numbers based on their types

查看:26
本文介绍了基于类型的泛型函数根据类型对数字求和的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设 x 和 y 的类型相同,并且可以是 BooleanIntDouble.这是我想写的函数:

Suppose x and y are of the same type and can be either Boolean, Int, or Double. Here is the function I want to write:

f(x, y) = 
   - if x == Boolean ==>   !x 
   - if x == Integer or x == Double ==> x+ y 

执行此操作的一种方法如下.我想知道是否有人对此有更好的想法.

One way of doing this can be the following. I was wondering if anyone has a better ideas on this.

def fun[T](x: T, y: T): T { 
   x match { 
       case xP: Boolean => !xP 
       case xP: Double => y match { case yP: Double =>  xP + yP }
       case xP: Int => y match { case yP: Int =>  xP + yP }
   }
}

我对此不满意的原因是 xy 具有相同的类型.我不应该需要两个 match-case;正确的?

The reason I am not happy with this is that x and y have the same type. I shouldn't need two match-cases; right?

另外两件事:

  • 仅仅设置 [T <: Int, Double, Boolean] 就可以将类型限制为三种类型吗?
  • 输出类型需要再次T.
  • Is it enough to just set [T <: Int, Double, Boolean] in order to restrict the type to only three types?
  • The output type needs to be again T.

推荐答案

这正是类型类旨在解决的问题.在你的情况下,你可以这样写:

This is precisely the kind of problem that type classes are designed to solve. In your case you could write something like this:

trait Add[A] {
  def apply(a: A, b: A): A
}

object Add {
  implicit val booleanAdd: Add[Boolean] = new Add[Boolean] {
    def apply(a: Boolean, b: Boolean): Boolean = !a
  }

  implicit def numericAdd[A: Numeric]: Add[A] = new Add[A] {
    def apply(a: A, b: A): A = implicitly[Numeric[A]].plus(a, b)
  }
}

Add[X] 类型的值描述了如何将 X 类型的两个值相加.您将 Add[X] 类型的隐式实例"放入您希望能够对其执行此操作的每个类型 X 的范围内.在本例中,我为 Boolean 和任何具有 scala.math.Numeric 实例的类型(标准库提供的类型类)提供了实例.如果您只需要 IntDouble 的实例,您可以简单地省略 numericAdd 并编写自己的 Add[Int]Add[Double] 实例.

A value of type Add[X] describes how to add two values of type X. You put implicit "instances" of type Add[X] in scope for every type X that you want to be able to perform this operation on. In this case I've provided instances for Boolean and any type that has an instance of scala.math.Numeric (a type class that's provided by the standard library). If you only wanted instances for Int and Double, you could simply leave out numericAdd and write your own Add[Int] and Add[Double] instances.

你会像这样写你的fun:

def fun[T: Add](x: T, y: T) = implicitly[Add[T]].apply(x, y)

像这样使用它:

scala> fun(true, false)
res0: Boolean = false

scala> fun(1, 2)
res1: Int = 3

scala> fun(0.01, 1.01)
res2: Double = 1.02

这具有非常显着的优势,即不会在运行时对尚未为其定义操作的类型造成影响.当您通过例如时,而不是使用 MatchError 异常使您的程序崩溃fun 的两个字符串,你会得到一个很好的编译失败:

This has the very significant advantage of not blowing up at runtime on types that you haven't defined the operation for. Instead of crashing your program with a MatchError exception when you pass e.g. two strings to fun, you get a nice compilation failure:

scala> fun("a", "b")
<console>:14: error: could not find implicit value for evidence parameter of type Add[String]
       fun("a", "b")
          ^

一般来说,type case"匹配(即看起来像 case x: X => ... 的匹配)在 Scala 中是个坏主意,而且几乎总是有更好的解决方案.通常它会涉及类型类.

In general "type case" matching (i.e. matches that look like case x: X => ...) are a bad idea in Scala, and there's almost always a better solution. Often it'll involve type classes.

这篇关于基于类型的泛型函数根据类型对数字求和的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆