Что такое признак FunctionN, представляющий функцию, принимающую параметр по имени?

Функция в Scala - это объект, который реализует одну из черт FunctionN. Например:

scala> def f(x: Int) = x * x
f: (x: Int)Int

scala> val ff = f _
ff: Int => Int = <function1>

scala> val fff: Function1[Int, Int] = f _
fff: Int => Int = <function1>

Пока все хорошо. Но что, если у нас есть функция, которая принимает параметр по имени? Конечно, он по-прежнему реализует одну из черт FunctionN:

scala> def g(x: => Int) = x * x
g: (x: => Int)Int

scala> val gg = g _
gg: => Int => Int = <function1>

scala> gg.isInstanceOf[Function1[_, _]]
res0: Boolean = true

Но что это за тип? Это не Function1[Int, Int]:

scala> val ggg: Function1[Int, Int] = g _
<console>:8: error: type mismatch;
 found   : => Int => Int
 required: Int => Int
       val ggg: Function1[Int, Int] = g _
                                      ^

И при этом это не Function1[Function0[Int], Int]:

scala> val ggg: Function1[Function0[Int], Int] = g _
<console>:8: error: type mismatch;
 found   : => Int => Int
 required: () => Int => Int
       val ggg: Function1[Function0[Int], Int] = g _
                                                 ^

И Function1[=> Int, Int] не удалось скомпилировать:

scala> val ggg: Function1[=> Int, Int] = g _
<console>:1: error: identifier expected but '=>' found.
       val ggg: Function1[=> Int, Int] = g _
                          ^

Так что это?

7 голосов | спросил Paul Butcher 24 42011vEurope/Moscow11bEurope/MoscowThu, 24 Nov 2011 04:27:50 +0400 2011, 04:27:50

2 ответа


0

Имя очень полезно, но небезопасно вне системы типов

Параметры по имени Scala - это синтаксический сахар, который делает код более читабельным, когда требуется ленивая оценка. Без него нам нужно было бы поставить "() =>" перед всем, что нужно было ленивым. Тем не менее, хотя это всего лишь функция 0 во время выполнения, на уровне системы типизации было бы проблематично, если бы вы могли определить что-либо, кроме параметра, имеющего тип по имени. Также помните, что черты FunctionN присутствуют в основном для реализации и взаимодействия Java, поскольку в Java и JVM не существует такого типа функции, как функция.

Быть явным

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

def g(x: => Int) = x * x
val ggg: (=> Int) => Int = g _

Более сложный набор текста

Типизацию по имени можно использовать только внутри части параметров объявлений типов функций. Сами типы функций могут затем использоваться внутри других параметризованных типов.

var funks: List[(=> Int) => Int] = Nil
funks ::= ggg
funks foreach { _ { println("hi"); 5 } }
ответил Neil Essy 24 42011vEurope/Moscow11bEurope/MoscowThu, 24 Nov 2011 06:17:01 +0400 2011, 06:17:01
0

Ответ Рекса Керра на этот вопрос дает Подсказка: аргумент по имени в конечном итоге преобразуется в Function0, но, вероятно, обрабатывается специально во время компиляции.

Вы можете проверить это:

scala> gg(sys.error("me"))
java.lang.RuntimeException: me
    at scala.sys.package$.error(package.scala:27)
    at $anonfun$1.apply(<console>:10)
    at $anonfun$1.apply(<console>:10)
    at scala.Function0$class.apply$mcI$sp(Function0.scala:34)
    at scala.runtime.AbstractFunction0.apply$mcI$sp
    ...

ИЗМЕНИТЬ

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

def test[A: Manifest](fun: Function1[A, Int]): Unit =
  println("Found " + implicitly[Manifest[A]])

scala> test(gg)
<console>:11: error: No Manifest available for => Int.
              test(gg)
                  ^
ответил 0__ 24 42011vEurope/Moscow11bEurope/MoscowThu, 24 Nov 2011 04:59:37 +0400 2011, 04:59:37

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

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132