有人能解释一下Scala中的隐式转换吗?

有人能解释一下Scala中的隐式转换吗?,scala,implicit-conversion,Scala,Implicit Conversion,更具体地说,如何将int转换为BigInt 在源代码中,它的内容如下: ... implicit def int2bigInt(i: Int): BigInt = apply(i) ... 如何调用此代码 我可以理解另一个示例:是如何工作的 在 定义如下: implicit def dateLiterals(date: Int) = new { import java.util.Date def Dec(year: Int) = new Date(year, 11, date) }

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

在源代码中,它的内容如下:

...
implicit def int2bigInt(i: Int): BigInt = apply(i)
...
如何调用此代码

我可以理解另一个示例:是如何工作的

定义如下:

implicit def dateLiterals(date: Int) = new {
  import java.util.Date  
  def Dec(year: Int) = new Date(year, 11, date)
}
int
get以
int
作为参数传递消息
Dec
时,系统会寻找另一种可以处理请求的方法,在这种情况下,
Dec(year:int)

问题1。我对日期文字的理解正确吗

问题2。它如何应用于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
因为我们已经将税率标记为隐式参数,并提供了一个隐式变量,可以在需要时填写,所以不需要指定税率。编译器会自动用税(15.00)(销售税)填写

在隐式转换的情况下,编译器会寻找一个方法,该方法可以接受它所拥有的类型并将其转换为所需的类型。这种转换在正常情况下是无法链接的,因此您必须一步到位

有两种情况下,隐式转换可能发挥作用。一个是在方法调用的参数中——如果类型错误,但可以将其转换为正确的类型(仅以一种方式),那么编译器将为您进行转换。另一种是方法调用——如果实际使用的类型没有可用的方法,但是您可以将其转换为具有该方法的类型,那么将进行转换,然后调用该方法

让我们看一个例子

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没有取整的
方法,因此
with tax(15.00)(0.15f)
应该不能调用一个方法(因为它返回一个
BigDecimal
)。但是我们定义了一个
货币
,它有一个
舍入的
方法,并且有一个到
货币
的转换,因此隐式转换填充了所有细节:
bigdec2currency(withTax(15.00)(0.15f))。舍入的

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


(注意:
int2bigInt
是在
BigInt
中定义的,因此要使用它,您必须
导入BigInt.\u
。而它又遵循
BigInt
对象的
apply(i:Int)
方法,该方法允许您编写
BigInt(5)
,并使其工作。)(而不是像Java中的
biginger
那样传递字符串)。

补充了@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
很有意义,但值得一提).

我认为您指的是隐式转换。隐式参数是一件稍有不同的事情。请澄清,它使用隐式if,如果它能使本来不会编译的代码这样做,而不仅仅是如果有一个隐式接受找到的类型作为其参数。scope thingy是一个红鲱鱼。Scala将搜索此类隐式ifn原始类的伴生对象,如果已推断目标类,则在目标类的伴生对象中。在这种情况下,由于目标类是显式BigInt,因此将搜索BigInt的伴生对象以查找隐式。我不想详细介绍作用域:)@丹尼尔:在这种情况下,正如你所说,范围不是问题。但是,如果OP希望去实现一些自己的隐式转换,我必须同意@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