有人可以解释我在Scala中的隐式转换吗?

Osc*_*Ryz 10 scala implicit-conversion

更具体地说,BigInt如何将convert int转换为BigInt?

在源代码中,它读取:

...
implicit def int2bigInt(i: Int): BigInt = apply(i)
...
Run Code Online (Sandbox Code Playgroud)

这个代码是如何被调用的?

我可以理解另一个样本:"日期文字"是如何工作的.

在.

val christmas = 24 Dec 2010  
Run Code Online (Sandbox Code Playgroud)

被定义为:

implicit def dateLiterals(date: Int) = new {
  import java.util.Date  
  def Dec(year: Int) = new Date(year, 11, date)
}
Run Code Online (Sandbox Code Playgroud)

intget Dec使用intas参数传递消息时,系统会查找另一个可以处理请求的方法,在本例中Dec(year:Int)

Q1.我是否正确理解日期文字?

Q2.它如何适用于BigInt?

谢谢

GCl*_*unt 15

当提供的类型与预期类型不匹配时,Scala编译器会查找标记为implicit的范围内的任何方法,该方法将提供的类型作为参数,并返回期望的类型作为结果.如果找到,它会在中间插入对方法的调用.在BigInt的情况下,假设你有一个方法

doSomethingWithBigInt(d:BigInt)=....
Run Code Online (Sandbox Code Playgroud)

你用整数调用它:

doSomethingWithBigInt(10)
Run Code Online (Sandbox Code Playgroud)

由于类型不匹配,Scala编译器将生成:

doSomethingWithBigInt(int2bigInt(10))
Run Code Online (Sandbox Code Playgroud)

假设隐式int2bigInt在范围内

  • 范围很重要的是红鲱鱼.如果已推断出该目标类,Scala将在原始类的伴随对象中以及目标类的伴随对象中搜索此类隐含.在这种情况下,由于目标类是显式BigInt,因此将搜索BigInt的对象伴随以查找含义. (3认同)
  • 为了澄清,它使用一个隐式*,如果它将生成不会编译的代码这样做*,而不仅仅是有一个隐式接受找到的类型作为它的参数. (2认同)

Rex*_*err 12

隐含的东西的意思是当显然只有一种正确的方法时,填写无聊的样板材料.

隐式参数的情况下,编译器从上下文中插入一个必须是您正在考虑的参数.例如,

case class TaxRate(rate: BigDecimal) { }
implicit var sales_tax = TaxRate(0.075)
def withTax(price: BigDecimal)(implicit tax: TaxRate) = price*(tax.rate+1)

scala> withTax(15.00)
res0: scala.math.BigDecimal = 16.1250
Run Code Online (Sandbox Code Playgroud)

由于我们已将税率标记为隐含参数,并提供了可在需要时填写的隐含变量,因此我们无需指定税率.编译器自动填写withTax(15.00)(sales_tax)

隐式转换的情况下,编译器会查找可以采用其具有的类型的方法,并将其转换为所需的类型.在正常情况下,此转换无法链接,因此您必须在一个步骤中获得所需内容.

有两种情况可能会发生隐式转换.一个是在方法调用的参数中 - 如果类型错误,但它可以转换为正确的类型(以一种方式),那么编译器将为您转换.另一个是在方法调用的情况下 - 如果实际使用的类型没有可用的方法,但你可以将它转换为具有该方法的类型,那么转换将发生,然后方法将叫做.

让我们看一下每个例子.

implicit def float2taxrate(f: Float) = TaxRate(BigDecimal(f))
scala> withTax(15.00)(0.15f)
res1: scala.math.BigDecimal = 17.250000089406967200
Run Code Online (Sandbox Code Playgroud)

在这里,我们称之为明确的税率0.15f.这与参数不匹配,参数必须是类型TaxRate,但编译器看到我们可以使用隐式将浮动变为税率float2taxrate.所以它为我们做了,呼唤withTax(15.00)(float2taxrate(0.15f))

现在是另一个例子.

class Currency(bd: BigDecimal) {
  def rounded = bd.setScale(2,BigDecimal.RoundingMode.HALF_EVEN)
}
implicit def bigdec2currency(bd: BigDecimal) = new Currency(bd)
scala> withTax(15.00)(0.15f).rounded
res66: scala.math.BigDecimal = 17.25
Run Code Online (Sandbox Code Playgroud)

BigDecimal没有rounded方法,因此withTax(15.00)(0.15f)不应该调用一个方法(因为它返回一个BigDecimal).但是我们已经定义了一个Currency确实有rounded方法和转换的方法Currency,因此隐式转换填充了所有细节:bigdec2currency(withTax(15.00)(0.15f)).rounded.

在转换为Intto 的情况下BigInt,编译器将在例如尝试添加时使用它7 + BigInt(5).这不会正常工作 - 7是一个Int并且Int不知道如何添加自己BigInt.但BigInt有一种方法+可以将自己添加到另一个BigInt.并且编译器看到只要它可以转换7为a BigInt,它就可以使用该方法.隐式转换允许转换,因此转换7 + BigInt(5)int2bigInt(7)+BigInt(5).

(注意:int2bigInt在内部定义BigInt,所以要使用它import BigInt._.它反过来又遵循对象的apply(i: Int)方法,BigInt这是让你编写BigInt(5)并让它工作的原因(而不是像BigInteger在Java中那样传递字符串) .)