简体   繁体   English

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

[英]Can someone explain me implicit conversions in Scala?

And more specifically how does the BigInt works for convert int to BigInt? 更具体地说, BigInt如何将convert int转换为BigInt?

In the source code it reads: 在源代码中,它读取:

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

How is this code invoked? 这个代码是如何被调用的?

I can understand how this other sample: "Date literals" works. 我可以理解另一个样本: “日期文字”是如何工作的。

In. 在。

val christmas = 24 Dec 2010  

Defined by: 被定义为:

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

When int get's passed the message Dec with an int as parameter, the system looks for another method that can handle the request, in this case Dec(year:Int) int get传递消息Dec并带有int作为参数时,系统会查找另一个可以处理请求的方法,在本例中为Dec(year:Int)

Q1. Q1。 Am I right in my understanding of Date literals? 我是否正确理解日期文字?

Q2. Q2。 How does it apply to BigInt? 它如何适用于BigInt?

Thanks 谢谢

When a the provided type doesn't match the expected type, the Scala compiler looks for any method in scope marked implicit that takes the provided type as parameter and returns the expected type as a result. 当提供的类型与预期类型不匹配时,Scala编译器会查找标记为implicit的范围内的任何方法,该方法将提供的类型作为参数,并返回期望的类型作为结果。 If found, it inserts the call to the method in between. 如果找到,它会在中间插入对方法的调用。 In the BigInt case, say you have a method 在BigInt的情况下,假设你有一个方法

doSomethingWithBigInt(d:BigInt)=....

And you call it with an integer: 你用整数调用它:

doSomethingWithBigInt(10)

As the types don't match, the Scala compiler will generate: 由于类型不匹配,Scala编译器将生成:

doSomethingWithBigInt(int2bigInt(10))

Assuming the implicit int2bigInt is in scope 假设隐式int2bigInt在范围内

The point of implicit stuff is to fill in boring boilerplate stuff when there is clearly only one right way to do it. 隐含的东西的意思是当显然只有一种正确的方法时,填写无聊的样板材料。

In the case of implicit parameters the compiler inserts a parameter from context that must be what you were thinking of. 隐式参数的情况下,编译器从上下文中插入一个必须是您正在考虑的参数。 For example, 例如,

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

Since we've marked the tax rate as an implicit parameter, and provided an implicit variable that can be filled in when needed, we don't need to specify the tax rate. 由于我们已将税率标记为隐含参数,并提供了可在需要时填写的隐含变量,因此我们无需指定税率。 The compiler automatically fills in withTax(15.00)(sales_tax) 编译器自动填写withTax(15.00)(sales_tax)

In the case of implicit conversions , the compiler looks for a method that can take a type that it has and convert it to the type that is needed. 隐式转换的情况下,编译器会查找可以采用其具有的类型的方法,并将其转换为所需的类型。 This conversion cannot be chained under normal circumstances, so you have to get to what you need in one step. 在正常情况下,此转换无法链接,因此您必须在一个步骤中获得所需内容。

There are two cases where implicit conversions are likely to come into play. 有两种情况可能会发生隐式转换。 One is in the parameter of a method call--if the type is wrong, but it can be converted to the right type (in exactly one way), then the compiler will convert for you. 一个是在方法调用的参数中 - 如果类型错误,但它可以转换为正确的类型(以完全一种方式),那么编译器将为您转换。 The other is in the presence of a method call--if the type actually used doesn't have the method available, but you could convert it to a type that does have that method, then the conversion will take place and then the method will be called. 另一个是在方法调用的情况下 - 如果实际使用的类型没有可用的方法,但是你可以将它转换为具有该方法的类型,那么转换将发生,然后方法将叫做。

Let's look at an example of each. 让我们看一下每个例子。

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

Here, we call an explicit tax rate of 0.15f . 在这里,我们称之为0.15f的明确税率。 That doesn't match the parameter, which must be of type TaxRate , but the compiler sees that we can turn floats into tax rates using the implicit float2taxrate . 这与参数不匹配,参数必须是TaxRate类型,但编译器发现我们可以使用隐式float2taxrate将浮点数转换为税率。 So it does it for us, calling withTax(15.00)(float2taxrate(0.15f)) 所以它为我们做了,调用withTax(15.00)(float2taxrate(0.15f))

Now the other example. 现在是另一个例子。

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 doesn't have a rounded method, so withTax(15.00)(0.15f) shouldn't be able to call one (as it returns a BigDecimal ). BigDecimal没有rounded方法,因此withTax(15.00)(0.15f)不应该调用一个(因为它返回一个BigDecimal )。 But we've defined a Currency that does have a rounded method, and a conversion to Currency , so the implicit conversion fills in all the details: bigdec2currency(withTax(15.00)(0.15f)).rounded . 但是,我们定义了一个Currency确实有一个rounded方法,以及转换为Currency ,因此隐式转换中的所有细节罢了,: bigdec2currency(withTax(15.00)(0.15f)).rounded

In the case of the conversion from Int to BigInt , the compiler will use it when, for example, it tries to add 7 + BigInt(5) . 在从Int转换为BigInt的情况下,编译器将使用它,例如,它尝试添加7 + BigInt(5) This isn't going to work normally-- 7 is an Int and Int doesn't know how to add itself to BigInt . 这不会正常工作 - 7IntInt不知道如何将自己添加到BigInt But BigInt has a method + that can add itself to another BigInt . BigInt有一个方法+可以将自己添加到另一个BigInt And the compiler sees that if only it could convert 7 to a BigInt , it could use that method. 并且编译器看到如果它只能将7转换为BigInt ,它可以使用该方法。 The implicit conversion allows that conversion, so it translates 7 + BigInt(5) into int2bigInt(7)+BigInt(5) . 隐式转换允许转换,因此它将7 + BigInt(5)转换为int2bigInt(7)+BigInt(5)

(Note: int2bigInt is defined inside BigInt , so to use it you have to import BigInt._ . And it in turn defers to the apply(i: Int) method of the BigInt object, which is what lets you write BigInt(5) and have it work (rather than having to pass a string as with BigInteger in Java).) (注意: int2bigInt是在BigInt定义的,所以要使用它你必须import BigInt._ 。然后它依次import BigInt._ BigInt对象的apply(i: Int)方法,这就是让你写BigInt(5)并让它工作(而不是像Java中的BigInteger那样传递字符串)。)

Complementing @GClaramunt's answer. 补充@ GClaramunt的答案。

Because it's way simpler to understand and grasp this concept by seeing a full example: 因为通过查看完整的示例来理解和掌握这个概念更简单:

// 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

I hope this example clarifies why and how one would want to use implicit conversions (not that I think converting String to Person makes a lot of sense but it's worth the illustration). 我希望这个例子说明了为什么以及如何使用隐式转换(不是我认为将String转换为Person很有意义,但值得举例说明)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM