Как работает ‘1 * BigInt(1)’ и как я могу сделать то же самое?

Я пытаюсь реализовать какой-то числовой тип, и я столкнулся с проблемой, что

mynum * 1

работает, но не

1 * mynum

Я попытался определить неявное преобразование, подобное этому

case class Num(v: Int) {
  def * (o: Int) = new Num(v*o)
}

implicit def int2Num(v: Int) = Num(v)

но это не работает, потому что я всегда получаю следующую ошибку:

scala> 1 * new Num(2)
<console>:14: error: overloaded method value * with alternatives:
  (x: Double)Double <and>
  (x: Float)Float <and>
  (x: Long)Long <and>
  (x: Int)Int <and>
  (x: Char)Int <and>
  (x: Short)Int <and>
  (x: Byte)Int
 cannot be applied to (Num)
              1 * new Num(2)
                ^

С другой стороны

1 * BigInt(1)

работает, поэтому должен быть способ, хотя я не мог определить решение, глядя на код.

Каков механизм, чтобы заставить его работать?

EDIT: я создал новый вопрос с реальной проблемой, с которой столкнулся, Почему неявное преобразование не учитывается в этом случае с универсальными параметрами?.


person soc    schedule 04.10.2011    source источник


Ответы (2)


Я думаю, что вам не хватает метода * в вашем классе Num, который принимает Num в качестве аргумента.

person Jens Schauder    schedule 04.10.2011
comment
Хорошее место! Я думаю, что я действительно слишком упростил свой пример. Похоже, моя реальная проблема другая, но с тем же сообщением об ошибке... - person soc; 04.10.2011

Когда приложение a.meth(args) терпит неудачу, компилятор ищет неявное представление от a до того, что имеет метод meth. Подойдет любое неявное значение или метод, соответствующий A => { def meth(...) }. Если он найден, код переписывается как view(a).meth(args).

Куда он смотрит? Сначала он просматривает текущую область видимости, состоящую из локально определенных имплицитов и импортированных имплицитов.

(На самом деле существует вторая фаза поиска, в которой рассматриваются методы преобразования с аргументами по имени, но это не очень важно для этого ответа.)

Если это не удается, он ищет в неявной области. Он состоит из сопутствующих объектов «частей» того типа, который мы ищем. В данном случае нам нужен A => { def meth(...) }, поэтому мы просто смотрим на объект-компаньон A (и его супертипы).

В магистрали Scala неявная область видимости немного расширена, чтобы включить сопутствующие объекты типы аргументов. Не уверен, что это уже было в 2.9.1, возможно, дружелюбный читатель поймет это для меня и обновит этот ответ.

Таким образом, 1 + BigInt(2) расширяется до BigInt.int2bigInt(1) + BigInt(2).

person retronym    schedule 04.10.2011
comment
Хороший ответ. Дополнительные сведения о имплицитах и ​​области действия см. в подробном руководстве Дэниела Собрала. - person Kipton Barros; 04.10.2011