Я читаю Scala Functions (часть другого тура по Scala ). В этом посте он заявил:
Методы и функции не одно и то же
Но он ничего не объяснил по этому поводу. Что он пытался сказать?
Я читаю Scala Functions (часть другого тура по Scala ). В этом посте он заявил:
Методы и функции не одно и то же
Но он ничего не объяснил по этому поводу. Что он пытался сказать?
Ответы:
Джим подробно рассказал об этом в своем блоге , но я публикую здесь брифинг для справки.
Сначала посмотрим, что нам скажет спецификация Scala. Глава 3 (типы) рассказывает нам о типах функций (3.2.9) и типах методов (3.3.1). Глава 4 (основные декларации) говорит о декларации и определениях значений (4.1), декларации и определениях переменных (4.2) и объявлениях и определениях функций (4.6). Глава 6 (выражения) говорит об анонимных функциях (6.23) и значениях метода (6.7). Любопытно, что о значениях функций говорится об одном разе в 3.2.9, и больше нигде.
Тип Функция представляет собой (примерно) тип формы (T1, ..., Tn) => U , которое является сокращением для признака
FunctionN
в стандартной библиотеке. Анонимные функции и методы Значения имеют функциональные типы, а функциональные типы могут использоваться как часть объявлений и определений значений, переменных и функций. Фактически, это может быть частью типа метода.Тип Метод представляет собой тип , не значение . Это означает, что нет значения - нет объекта, нет экземпляра - с типом метода. Как упоминалось выше, значение метода на самом деле имеет тип функции . Тип метода - это
def
объявление - все о,def
кроме его тела.Значение декларация и определение и объявление переменное и определения являются
val
иvar
заявление, в том числе как типа и значения - которое может быть, соответственно, Функция Тип и Анонимные функции или метода значение . Обратите внимание, что в JVM эти (значения методов) реализованы с помощью того, что Java называет «методами».Объявление функции - это
def
объявление, включая тип и тело . Часть type является типом метода, а тело является выражением или блоком . Это также реализовано в JVM с помощью того, что Java называет «методами».Наконец, анонимная функция является экземпляром типа функции (т. Е. Экземпляром признака
FunctionN
), а значение метода - это то же самое! Различие состоит в том, что значение метода создается из методов, либо путем добавления нижнего подчеркивания (m _
это значение метода, соответствующее «объявлению функции» (def
)m
), либо с помощью процесса, называемого eta-extension , который похож на автоматическое приведение из метода. функционировать.Это то, что говорят спецификации, поэтому позвольте мне сказать об этом заранее: мы не используем эту терминологию! Это приводит к слишком большой путанице между так называемым «объявлением функции» , которое является частью программы (глава 4 - основные объявления), и «анонимной функцией» , которая является выражением, и «типом функции» , который ну вид - черта.
Приведенная ниже терминология, используемая опытными программистами Scala, вносит одно изменение в терминологию спецификации: вместо того, чтобы произносить объявление функции , мы говорим « метод» . Или даже объявление метода. Кроме того, следует отметить , что значение декларация и объявление переменного также методы для практических целей.
Итак, учитывая вышеизложенное изменение терминологии, вот практическое объяснение различия.
Функция представляет собой объект , который включает в себя один из
FunctionX
признаков, таких , какFunction0
,Function1
,Function2
и т.д. Это может быть в том числе ,PartialFunction
а также, которые на самом деле проходитFunction1
.Давайте посмотрим тип подписи для одного из этих признаков:
Эта черта имеет один абстрактный метод (он также имеет несколько конкретных методов):
И это говорит нам все, что нужно знать об этом. Функция имеет
apply
метод , который принимает N параметры типов Т1 , Т2 , ..., TN , и возвращает что - то типаR
. Это противоречиво по параметрам, которые он получает, и ко-вариант по результату.Эта дисперсия означает, что
Function1[Seq[T], String]
является подтипомFunction1[List[T], AnyRef]
. Быть подтипом означает, что его можно использовать вместо него. Легко увидеть, что если я собираюсь позвонитьf(List(1, 2, 3))
и ожидать ответного звонка, то подойдетAnyRef
любой из этих двух типов.Теперь, в чем сходство метода и функции? Что ж, если
f
это функция иm
метод локальный для области видимости, то оба могут быть вызваны так:Эти вызовы на самом деле разные, потому что первый - просто синтаксический сахар. Scala расширяет его до:
Что, конечно, является вызовом метода для объекта
f
. У функций также есть и другие синтаксические сахара в качестве преимущества: функциональные литералы (на самом деле их два) и(T1, T2) => R
сигнатуры типов. Например:Другое сходство между методом и функцией заключается в том, что первое можно легко преобразовать во второе:
Scala расширит это , предполагая, что
m
тип находится(List[Int])AnyRef
в (Scala 2.7):В Scala 2.8 он фактически использует
AbstractFunction1
класс для уменьшения размеров классов.Обратите внимание, что нельзя преобразовать наоборот - из функции в метод.
Методы, однако, имеют одно большое преимущество (ну, два - они могут быть немного быстрее): они могут получать параметры типа . Например, в то время как
f
выше может обязательно указать типList
его получения (List[Int]
в примере),m
может параметризовать его:Я думаю, что это в значительной степени охватывает все, но я буду рад дополнить это ответами на любые вопросы, которые могут остаться.
источник
val f = m
компилятором,val f = new AnyRef with Function1[List[Int], AnyRef] { def apply(x$1: List[Int]) = this.m(x$1) }
вы должны указать, что методthis
внутриapply
относится не кAnyRef
объекту, а к объекту, в методе которогоval f = m _
он оценивается ( так сказать, как внешний).this
), посколькуthis
входит в число значений, которые фиксируются замыканием (например,return
как указано ниже).Одно большое практическое различие между методом и функцией заключается в том, что
return
означает.return
только когда-либо возвращается из метода. Например:При возврате из функции, определенной в методе, выполняется нелокальный возврат:
Принимая во внимание, что возвращение из локального метода возвращает только из этого метода.
источник
for (a <- List(1, 2, 3)) { return ... }
? Это обезвожено до закрытия.return
возвращаемое значение из функции и некоторую формуescape
илиbreak
илиcontinue
возвращать из методов.Программирование в Scala Second Edition. Мартин Одерски - Лекс Ложка - Билл Веннерс
источник
Скажем, у вас есть список
Определить метод
Определить функцию
Метод, принимающий аргумент
Определение функции с помощью val
Аргумент к функции необязателен
Аргумент метода обязателен
Проверьте следующий учебник, который объясняет передачу других различий с примерами, такими как другой пример diff с методом против функции, использование функции в качестве переменных, создание функции, возвращающей функцию
источник
Функции не поддерживают параметры по умолчанию. Методы делают. Преобразование из метода в функцию теряет значения параметров по умолчанию. (Scala 2.8.1)
источник
Существует хорошая статья здесь , из которых большинство моих описаний принимаются. Просто краткое сравнение функций и методов относительно моего понимания. Надеюсь, поможет:
Функции : они в основном объект. Точнее, функции - это объекты с методом apply; Таким образом, они немного медленнее, чем методы из-за их накладных расходов. Это похоже на статические методы в том смысле, что они не зависят от вызываемого объекта. Простой пример функции выглядит так:
Строка выше - это ничто иное, как присвоение одного объекта другому, например, object1 = object2. На самом деле object2 в нашем примере является анонимной функцией, и левая сторона получает тип объекта из-за этого. Следовательно, теперь f1 является объектом (функцией). На самом деле анонимная функция является экземпляром Function1 [Int, Int], что означает функцию с 1 параметром типа Int и возвращаемым значением типа Int. Вызов f1 без аргументов даст нам подпись анонимной функции (Int => Int =)
Методы : они не являются объектами, но присваиваются экземпляру класса, то есть объекту. Точно так же, как метод в java или функции-члены в c ++ (как отметил Раффи Хачатурян в комментарии к этому вопросу ) и т. Д. Простой пример метода такой же, как и ниже:
Строка выше - это не простое присвоение значения, а определение метода. Когда вы вызываете этот метод со значением 2, как во второй строке, x заменяется на 2, и результат будет вычислен, и вы получите 4 в качестве вывода. Здесь вы получите ошибку, если просто напишите m1, потому что это метод и нужно ввести значение. Используя _, вы можете назначить метод для функции, как показано ниже:
источник
Вот отличный пост Роба Норриса, который объясняет разницу, вот TL; DR
со следующим определением:
В двух словах ( выдержка из блога ):
Когда мы определяем метод, мы видим, что мы не можем присвоить его a
val
.Отметим также тип из
add1
, который не выглядит нормально; Вы не можете объявить переменную типа(n: Int)Int
. Методы не являются значениями.Однако, добавив постфиксный оператор η-расширения (η произносится как «eta»), мы можем превратить метод в значение функции. Обратите внимание на тип
f
.Результатом
_
является выполнение эквивалента следующего: мы создаемFunction1
экземпляр, который делегирует нашему методу.источник
В Scala 2.13, в отличие от функций, методы могут принимать / возвращать
Однако эти ограничения будут сняты в Дотти (Scala 3) по типам функций полиморфных # 4672 , например, точечная версия 0.23.0-RC1 позволяет следующий синтаксис
Введите параметры
Неявные параметры ( контекстные параметры)
Зависимые типы
Дополнительные примеры см. В разделе tests / run / polymorphic-functions.scala.
источник
Практически, программист Scala должен знать только следующие три правила, чтобы правильно использовать функции и методы:
def
и функциональные литералы, определенные=>
как функции, являются функциями. Это определено на стр. 143, глава 8 книги по программированию в Scala, 4-е издание.someNumber.foreach(println)
После четырех выпусков «Программирование в Scala» людям по-прежнему трудно разграничить два важных понятия: функция и значение функции, потому что во всех выпусках нет четкого объяснения. Спецификация языка слишком сложна. Я обнаружил, что приведенные выше правила просты и точны.
источник