类型参数和数字加宽 [英] type parameters and numeric widening

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

问题描述

正如我们所知,我们可以将两个不同的 Numeric 类型的数字相加(减/乘/等),结果将是这两种类型中较宽的一个,无论它们的顺序如何.

As we know, we can add (subtract/multiply/etc.) two numbers of different Numeric types and the result will be the wider of the two types, regardless of their order.

33F + 9L  // Float + Long == Float
33L + 9F  // Long + Float == Float

这是因为 7 个 Numeric 类(ByteShortCharInt, Long, Float, Double) 有 7 种不同的 +() 方法(和 -()*() 等),每个 Numeric 类型都可以作为传递参数接收.[有一个额外的 +() 方法来处理 String 参数,但这里不需要我们关注.]

This is because each of the 7 Numeric classes (Byte, Short, Char, Int, Long, Float, Double) has 7 different +() methods (and -(), *(), etc), one for every Numeric type that can be received as a passed parameter. [There's an extra +() method for handling a String parameter, but that need not concern us here.]

现在考虑以下几点:

implicit class PlusOrMinus[T: Numeric](a: T) {
  import Numeric.Implicits._
  def +-(b: T) = if (util.Random.nextBoolean) a+b else a-b
}

如果两个操作数的类型相同,则此方法有效,但如果第一个操作数的类型比第二个操作数的类型宽,则此方法也有效.

This works if the two operands are the same type, but it also works if the type of the 1st operand is wider than the type of the 2nd.

11F +- 2L  // result: Float = 9.0 or 13.0

我相信这里发生的事情是编译器使用 弱一致性实现数字加宽 在第二个操作数(b 参数)上传递给 +-() 方法.

I believe what's happening here is that the compiler uses weak conformance to achieve numeric widening on the 2nd operand (the b parameter) as it is passed to the +-() method.

但是第一个操作数不会被扩展以匹配第二个操作数.它甚至不会编译.

But the 1st operand won't be widened to match the 2nd. It won't even compile.

11L +- 2F  // Error: type mismatch; found: Float(2.0) required: Long

有没有办法绕过这个限制?

Is there any way around this limitatiion?

我不能为 b 参数使用不同的类型参数 (def +-[U: Numeric](b: U) = ...) 因为Numeric,通过类型参数表示,只能加减它自己的类型.

I can't use a different type parameter for the b argument (def +-[U: Numeric](b: U) = ...) because a Numeric, expressed via a type parameter, can only add/subtract it's own type.

是使用 7 种不同方法(def +-(b:Short))创建 7 个不同类(PlusOrMinusShort/Int/Long/ 等)的唯一解决方案,def +-(b:Int)def +-(b:Long) 等)?

Is the only solution to create 7 different classes (PlusOrMinusShort/Int/Long/etc.) with 7 different methods (def +-(b:Short), def +-(b:Int), def +-(b:Long), etc.)?

推荐答案

这里有一个方法:

implicit class PlusOrMinus[T: Numeric](a: T) {
  import Numeric.Implicits._
  def +-(b: T) = plusOrMinus(a,b)
  def +-[U: Numeric](b: U)(implicit ev: T => U) = plusOrMinus[U](a,b)

  private def plusOrMinus[W: Numeric](a: W, b: W): W =
    if (util.Random.nextBoolean) a+b else a-b
}

然后,通过这个,我得到以下交互:

Then, with this, I get the following interaction:

scala> 11F +- 2L
res0: Float = 9.0

scala> 11L +- 2F
res1: Float = 9.0

<小时>

这个想法是,如果我可以只有一个函数 plusOrMinus,那么整个问题就变得微不足道了,因为对于任何一个参数都可能发生相同的扩展.定义了这样一个函数后,问题就变成了如何将其嵌入到隐式类中,以中缀形式使用.


The idea is that if I could just have a function plusOrMinus, this whole problem would be trivial, since the same widening could happen for either arguments. After defining such a function, the problem becomes how to embed it into an implicit class to use it in an infix form.

这里,我们只有两种情况:要么需要加宽第二个参数,要么需要加宽隐式类包装的参数.第一种情况包含在第一个 +- 方法中(出于您在上面观察到的原因).然而,对于第二个,我们需要明确说明存在一些可能的转换,并将转换的泛型类型传递给 plusOrMinus.

Here, we have only two cases: either the second argument needs to be widened or the argument wrapped by the implicit class needs to be widened. The first of these cases is covered by the first +- method (for the reasons you observed above). For the second, however, we need to explicitly say that there is some conversion that is possible and pass the generic type of the conversion to plusOrMinus.

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

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