Неявное определение Any для Function добавляет метод apply к классам - PullRequest
2 голосов
/ 20 января 2011

Взгляните на следующее и посмотрите, сможете ли вы в этом разобраться:

Welcome to Scala version 2.8.1.final (Java HotSpot(TM) Client VM, Java 1.6.0_17).
Type in expressions to have them evaluated.
Type :help for more information.

scala> class A
defined class A

scala> val a = new A
a: A = A@1643e4b

scala> a.apply("foo")
<console>:8: error: value apply is not a member of A
       a.apply("foo")
         ^

Здесь все выглядит вполне нормально. Но затем мы добавляем неявное преобразование.

scala> implicit def anyToFunc(any: Any) = { x: String => "bar" }
anyToFunc: (any: Any)(String) => java.lang.String

scala> a.apply("foo")
res1: java.lang.String = bar

И вдруг A имеет метод apply, который принимает аргумент того же типа, который принимает функция, которую возвращает неявный!

Давайте проверим это немного подробнее:

scala> class B { override def toString = "an instance of class B" }
defined class B

scala> implicit def anyToFunc(any: Any) = { x: String =>
     | println("any is " + any.toString)
     | println("x is " + x)
     | "bar" }
anyToFunc: (any: Any)(String) => java.lang.String

scala> val b = new B
b: B = an instance of class B

scala> b.apply("test")
any is an instance of class B
x is test
res8: java.lang.String = bar

Это «скрытая функция»? Если да, то как его использовать?

Ответы [ 3 ]

5 голосов
/ 20 января 2011

Вы звоните apply на объект типа A.A не имеет apply метода.Однако A неявно преобразуется в Function[String, String], который имеет метод apply.Таким образом, применяется неявное преобразование и apply вызывается для преобразованного объекта.

В этой функции нет ничего волшебного или скрытого.Если у объекта нет метода, который вы вызываете, но он неявно конвертируется в тот, который имеет, он будет преобразован.Это именно то, для чего нужны неявные преобразования.

3 голосов
/ 20 января 2011

любая функция, созданная в Scala, преобразуется в класс с помощью метода apply.Тогда сокращение для вызова apply пропускает его.

class A{
    val a = (x:String) => x * 2
}
скомпилируйте это и увидите, что созданы два файла, A.class и A$$anonfun$1.class.Проверьте файл класса с помощью javap, и вы увидите это
Compiled from "Fun.scala"
public final class A$$anonfun$1 extends scala.runtime.AbstractFunction1 implements java.io.Serializable{
    public static final long serialVersionUID;
    public static {};
    public final java.lang.String apply(java.lang.String);
    public final java.lang.Object apply(java.lang.Object);
    public A$$anonfun$1(A);
}
Важная строка - public final java.lang.String apply(java.lang.String);.Это называется либо a("string"), либо a.apply("string").Да, вы можете преобразовать что-либо в функцию с помощью implicit def s, но это не имеет особого смысла.Обычно используется в разных случаях: Прокачай мою библиотеку
1 голос
/ 20 января 2011

Это не столько скрытая особенность, сколько ожидаемое поведение неявных определений и метода apply.Важно отметить, что метод apply - это специальный метод, который вызывается при передаче аргументов непосредственно объекту.Поэтому, когда в вашем примере вы делаете следующее:

b.apply("Test")

Это будет эквивалентно b("test").Function определяет apply, поэтому мы можем делать такие приятные вещи, как:

val addOne = (b : Int) => b + 1
addOne(10)

Итак, когда вы пытаетесь вызвать apply для экземпляра B, компилятор сначала смотрит, есть ли у B метод apply, затем проверяет, применяется ли метод к суперклассу B, затем ищет неявное для чего-то, у которого есть метод apply.Это цель неявных определений.Поскольку Function1 имеет метод apply, вызывается неявное преобразование и также вызывается метод apply функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...