Кто-то может объяснить меня неявные преобразования в Scala?

И более конкретно как делает работы 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?

Спасибо

10
задан missingfaktor 19 May 2010 в 01:03
поделиться

2 ответа

Смысл неявных вещей состоит в том, чтобы заполнить скучный шаблонный материал, когда явно есть только один правильный способ сделать это.

В случае неявных параметров компилятор вставляет параметр из контекста, который должен быть тем, о чем вы думали. Например,

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).)

12
ответ дан 3 December 2019 в 15:34
поделиться

Когда предоставленный тип не совпадает с ожидаемым типом, компилятор Scala ищет любой метод в области видимости с пометкой implicit, который принимает предоставленный тип в качестве параметра и возвращает ожидаемый тип в качестве результата. Если он найден, то вставляет вызов метода между ними. В случае с BigInt, допустим, у вас есть метод

doSomethingWithBigInt(d:BigInt)=....

И вы вызываете его с целым числом:

doSomethingWithBigInt(10)

Поскольку типы не совпадают, компилятор Scala выдаст:

doSomethingWithBigInt(int2bigInt(10))

Предполагая, что неявный int2bigInt находится в области видимости

15
ответ дан 3 December 2019 в 15:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: