И более конкретно как делает работы BigInt для интервала преобразования к 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
доберитесь передал сообщение Dec
с int
как параметр, система ищет другой метод, который может обработать запрос в этом случае Dec(year:Int)
Q1. Действительно ли я прав в своем понимании литералов Даты?
Q2. Как это относится к BigInt?
Спасибо
Смысл неявных вещей состоит в том, чтобы заполнить скучный шаблонный материал, когда явно есть только один правильный способ сделать это.
В случае неявных параметров компилятор вставляет параметр из контекста, который должен быть тем, о чем вы думали. Например,
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 не имеет метода округления
, поэтому withTax (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 ._
. А он, в свою очередь, подчиняется apply (i: Int)
объекта BigInt
, который позволяет вам написать BigInt (5)
и заставить его работать (вместо того, чтобы передавать строка как с BigInteger
в Java).)
Когда предоставленный тип не совпадает с ожидаемым типом, компилятор Scala ищет любой метод в области видимости с пометкой implicit, который принимает предоставленный тип в качестве параметра и возвращает ожидаемый тип в качестве результата. Если он найден, то вставляет вызов метода между ними. В случае с BigInt, допустим, у вас есть метод
doSomethingWithBigInt(d:BigInt)=....
И вы вызываете его с целым числом:
doSomethingWithBigInt(10)
Поскольку типы не совпадают, компилятор Scala выдаст:
doSomethingWithBigInt(int2bigInt(10))
Предполагая, что неявный int2bigInt находится в области видимости