Почему этот почти идентичный класс значений не работает?

Как и было обещано на http://docs.scala-lang.org/overviews/core/value-classes.html, это работает:

class Wrapper(val self: Int) extends AnyVal {
  def toHexString: String = java.lang.Integer.toHexString(self)
}
println(12.toHexString)

Но это не компилируется:

class Wrapper(val self: Int) extends AnyVal {
  def whyNot:      String = java.lang.Integer.toHexString(self)
}
println(12.whyNot)

Почему нет? Единственное, что я изменил, это название метода!

Вот сообщение об ошибке:

error: value whyNot is not a member of Int
    println(12.whyNot)
               ^

Да, я перепроверил наличие символов Unicode внутри whyNot.


person Ben Kovitz    schedule 25.01.2015    source источник
comment
Я только что нашел подсказку: рабочий все еще работает, даже если я закомментирую class Wrapper { ... }. Судя по всему, Scala вызывает встроенный класс RichInt, но игнорирует мой класс Wrapper.   -  person Ben Kovitz    schedule 25.01.2015


Ответы (2)


Predef.scala определяет неявное преобразование из Int в RichInt:

  @inline implicit def intWrapper(x: Int)         = new runtime.RichInt(x)

Когда вы вызываете println(12.toHexString), он не смотрит на ваш Wrapper, он выполняет неявное преобразование в RichInt и использует метод определены здесь.

Если вам нужно собственное неявное преобразование, вам нужно определить его с помощью implicit ключевого слова:

implicit class Wrapper(val self: Int) extends AnyVal {
  def whyNot:      String = java.lang.Integer.toHexString(self)
}
println(12.whyNot)  // prints "c"
person dhg    schedule 25.01.2015
comment
Ах, это все объясняет, в том числе и то, почему в источнике RichInt нет implicit. И действительно, когда я добавляю implicit перед class Wrapper, это работает. Спасибо. - person Ben Kovitz; 25.01.2015

Я не понимаю, почему вы думаете, что он должен компилироваться.

Целые числа не имеют метода whyNot. У Wrapper есть метод whyNot, но 12 — это Int, а не Wrapper.

Вам нужно вызвать whyNot для объекта Wrapper:

new Wrapper(12).whyNot
// => "c"
person Jörg W Mittag    schedule 25.01.2015
comment
Я надеюсь заставить whyNot работать с Int, автоматически оборачивая их, как в примере с 3.toHexString здесь. Нужно ли ставить implicit перед class Wrapper? Если да, то знаете ли вы, почему перед RichInt нет implicit здесь? - person Ben Kovitz; 25.01.2015