[英]Can someone explain me implicit conversions in Scala?
更具体地说, BigInt如何将convert 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)
}
当int
get传递消息Dec
并带有int
作为参数时,系统会查找另一个可以处理请求的方法,在本例中为Dec(year:Int)
Q1。 我是否正确理解日期文字?
Q2。 它如何适用于BigInt?
谢谢
当提供的类型与预期类型不匹配时,Scala编译器会查找标记为implicit的范围内的任何方法,该方法将提供的类型作为参数,并返回期望的类型作为结果。 如果找到,它会在中间插入对方法的调用。 在BigInt的情况下,假设你有一个方法
doSomethingWithBigInt(d:BigInt)=....
你用整数调用它:
doSomethingWithBigInt(10)
由于类型不匹配,Scala编译器将生成:
doSomethingWithBigInt(int2bigInt(10))
假设隐式int2bigInt在范围内
隐含的东西的意思是当显然只有一种正确的方法时,填写无聊的样板材料。
在隐式参数的情况下,编译器从上下文中插入一个必须是您正在考虑的参数。 例如,
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
的明确税率。 这与参数不匹配,参数必须是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)
不应该调用一个(因为它返回一个BigDecimal
)。 但是,我们定义了一个Currency
确实有一个rounded
方法,以及转换为Currency
,因此隐式转换中的所有细节罢了,: bigdec2currency(withTax(15.00)(0.15f)).rounded
。
在从Int
转换为BigInt
的情况下,编译器将使用它,例如,它尝试添加7 + BigInt(5)
。 这不会正常工作 - 7
是Int
和Int
不知道如何将自己添加到BigInt
。 但BigInt
有一个方法+
可以将自己添加到另一个BigInt
。 并且编译器看到如果它只能将7
转换为BigInt
,它可以使用该方法。 隐式转换允许转换,因此它将7 + BigInt(5)
转换为int2bigInt(7)+BigInt(5)
。
(注意: int2bigInt
是在BigInt
定义的,所以要使用它你必须import BigInt._
。然后它依次import BigInt._
BigInt
对象的apply(i: Int)
方法,这就是让你写BigInt(5)
并让它工作(而不是像Java中的BigInteger
那样传递字符串)。)
补充@ 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
我希望这个例子说明了为什么以及如何使用隐式转换(不是我认为将String
转换为Person
很有意义,但值得举例说明)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.