代码之家  ›  专栏  ›  技术社区  ›  OscarRyz

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

  •  7
  • OscarRyz  · 技术社区  · 15 年前

    更具体地说, BigInt 用于将int转换为bigint?

    在源代码中,它读作:

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

    如何调用此代码?

    我能理解另一个样本: "Date literals" 作品。

    在。

    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 用一个 内景 作为参数,系统会寻找另一个可以处理请求的方法,在本例中 Dec(year:Int)

    第一季度。我对日期文字的理解对吗?

    问题2。它如何应用于bigint?

    谢谢

    3 回复  |  直到 15 年前
        1
  •  15
  •   GClaramunt    15 年前

    当提供的类型与预期的类型不匹配时,scala编译器会在标记为implicit的作用域中查找以提供的类型为参数并返回预期类型的任何方法。如果找到,则在中间插入对该方法的调用。 在bigint的例子中,假设你有一个方法

    doSomethingWithBigInt(d:BigInt)=....
    

    你用一个整数来称呼它:

    doSomethingWithBigInt(10)
    

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

    doSomethingWithBigInt(int2bigInt(10))
    

    假设隐式int2bigint在范围内

        2
  •  12
  •   Rex Kerr    15 年前

    隐式方法的要点是在只有一种正确的方法时填充无聊的样板文件。

    在这种情况下 隐式参数 编译器从上下文中插入一个参数,这一定是您所想的。例如,

    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 有一个 圆形的 方法,并转换为 货币 ,因此隐式转换将填充所有详细信息: bigdec2currency(withTax(15.00)(0.15f)).rounded 是的。

    如果从 Int BigInt ,例如,当编译器试图添加 7 + BigInt(5) 是的。这不正常-- 7 是一个 int int 不知道如何将自己添加到 大整数 是的。但是 大整数 有办法 + 会把自己添加到另一个 大整数 是的。编译器看到如果它能转换 7 给一个 大整数 ,它可以使用这种方法。隐式转换允许该转换,因此它转换 7+大整数(5) 进入之内 int2bigInt(7)+BigInt(5) 是的。

    (注: int2bigInt 在内部定义 大整数 ,所以要使用它你必须 import BigInt._ 是的。它反过来又服从于 apply(i: Int) 方法 大整数 对象,这是允许您编写 BigInt(5) 让它工作(而不是像 BigInteger 在Java中)。

        3
  •  1
  •   thiagoh    6 年前

    补充@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 很有意义,但值得说明)。