В чем разница между созданием разных функций

Этот вопрос тесно связан с моим другим вопросом (и может привести к тому, что я решу его), но определенно отличается.

как разрешить передачу в =› AnyRef и вызвать эту функцию

Я играл с различными созданиями функций, и у меня, честно говоря, возникли проблемы с созданием анонимной функции типа => AnyRef и => String. Я могу создать функцию типа () => AnyRef и () => String, я думаю.

Пример 1 У меня есть следующий код

def debugLazyTest2(msg: => String) : Unit = {
  System.out.println(msg)
}

//and client code
  val function: () => String = () => {
    executed = true
    "asdf"+executed+" hi there"
  }
  log2.debugLazyTest2(function)

но ошибка компиляции говорит, что найдено: () => String, что имеет смысл, но затем говорит «требуется: строка» вместо «требуется: => строка»

Что здесь происходит?

Пример 2, чтобы стать еще более странным, у меня есть этот код, который компилируется, а выше не компилируется

def debugLazyTest(msg: => AnyRef) : Unit = {
  System.out.println(msg.toString)
}

//and client code which compiles!!!!
  val function: () => AnyRef = () => {
    executed = true
    "asdf"+executed+" hi there"
  }
  log2.debugLazyTest(function)

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

Любые идеи относительно того, что здесь происходит?

спасибо, Дин


person Dean Hiller    schedule 12.08.2014    source источник


Ответы (2)


Если бы вы написали это, это сработало бы:

log2.debugLazyTest2(function())

msg — это параметр по имени, а не функция. Вы должны передать выражение типа String (или AnyRef во втором примере)

Второй пример компилируется, потому что () => AnyRef, который вы передаете, на самом деле также является AnyRef, поскольку функция является AnyRef. Но тогда печатается сама функция, а не результат ее выполнения.

person Patrick Prémont    schedule 12.08.2014
comment
это замечательно. Я не понимал, что это синтаксис для имени, и думал, что он передает функцию. Это проясняет для меня ситуацию......большое спасибо!!!! - person Dean Hiller; 13.08.2014

Рассмотрим следующий код:

scala> def test(x: String) = debugLazyTest2(x)
test: (x: String)Unit

Если мы затем запустим (в Scala 2.11.2):

:javap test

И немного обрезаем сгенерированный вывод, мы видим следующее:

  public void test(java.lang.String);
    flags: ACC_PUBLIC
    Code:
      stack=4, locals=2, args_size=2
         0: getstatic     #19                 // Field .MODULE$:L;
         3: new           #21                 // class $anonfun$test$1
         6: dup
         7: aload_1
         8: invokespecial #23                 // Method $anonfun$test$1."<init>":(Ljava/lang/String;)V
        11: invokevirtual #27                 // Method .debugLazyTest2:(Lscala/Function0;)V
        14: return
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      15     0  this   L;
               0      15     1     x   Ljava/lang/String;
      LineNumberTable:
        line 8: 0

И далее рассматриваем подпись для debugLazyTest2:

 public void debugLazyTest2(scala.Function0<java.lang.String>);

Ключевая строка:

         3: new           #21                 // class $anonfun$test$1

Если я правильно читаю код, мы создаем новый экземпляр класса $anonfun$test$1 и передаем этот новый анонимный Function0[String] в debugLazyTest2. Это делает наш метод test эквивалентным следующему:

def test(x: String) = debugLazyTest2(new Function0[String] {
    def apply(): String = x
})

Когда мы рассматриваем передачу экземпляра Function0[String] в debugLazyTest2, выполняя одно и то же преобразование, мы получаем:

debugLazyTest2(function)

который становится:

debugLazyTest2(new Function0[String] {
    def apply(): Function0[String] = function
})

который, естественно, не компилируется, потому что apply(): Function0[String] не соответствует требуемому типу apply(): String (отсюда и сообщение об ошибке).

На самом деле работает вызов функции вместо возврата:

debugLazyTest2(function())

становится:

debugLazyTest2(new Function0[String] {
    def apply(): String = function()
})
person Sean Vieira    schedule 12.08.2014