12

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

在源代码中它写道:

...
implicit def int2bigInt(i: Int): BigInt = apply(i)
...

这段代码是如何调用的?

我可以理解这个其他示例:“日期文字”是如何工作的。

在。

val christmas = 24 Dec 2010  

被定义为:

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

intget 传递Dec带有intas 参数的消息时,系统会寻找另一个可以处理请求的方法,在这种情况下Dec(year:Int)

Q1。我对日期文字的理解是否正确?

Q2。它如何应用于 BigInt?

谢谢

4

3 回答 3

17

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

doSomethingWithBigInt(d:BigInt)=....

你用一个整数调用它:

doSomethingWithBigInt(10)

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

doSomethingWithBigInt(int2bigInt(10))

假设隐式 int2bigInt 在范围内

于 2010-05-18T22:56:37.560 回答
14

隐含的东西的重点是在显然只有一种正确的方法时填充无聊的样板文件。

隐式参数的情况下,编译器从上下文中插入一个参数,该参数必须是您所想的。例如,

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

由于我们已经将税率标记为隐式参数,并提供了一个可以在需要时填写的隐式变量,因此我们不需要指定税率。编译器自动填写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

在这里,我们称显性税率为0.15f。这与必须为 type 的参数不匹配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

BigDecimal 没有rounded方法,因此withTax(15.00)(0.15f)不应该调用一个方法(因为它返回 a 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 中那样传递一个字符串) .)

于 2010-05-18T23:46:32.173 回答
2

补充@GClaramunt 的回答。

因为通过查看完整示例可以更简单地理解和掌握这个概念:

// define a class
case class Person(firstName: String, lastName: String)

// must import this to enable implicit conversions
import scala.language.implicitConversions

// define the implicit conversion. String to Person in this case
implicit def stringToPerson(name:String) = {
  val fields = name.split(" ");
  Person(fields(0), fields(1))
}

// method using the implicit conversion  
def getPerson(fullName:String): Person = fullName

val fooBar = getPerson("foo bar")
println(fooBar.getClass())  // class Person
println(fooBar.firstName)  // foo
println(fooBar.lastName)  // bar

我希望这个例子能阐明为什么以及如何使用隐式转换(不是我认为转换StringPerson很有意义,但值得说明)。

于 2018-12-28T03:57:38.540 回答