Вы, кажется, наткнулись на ответ. Во всяком случае, я постараюсь прояснить это.
Вы можете опускать точку при использовании префиксной, инфиксной и постфиксной нотации - так называемой нотации оператора . При использовании обозначений операторов и только тогда вы можете опустить круглые скобки, если методу передано менее двух параметров.
Теперь обозначение оператора - это обозначение для вызова метода , что означает, что его нельзя использовать при отсутствии вызываемого объекта.
Кратко опишу обозначения.
Префикс:
Только ~
, !
, +
и -
может быть использовано в Приставка обозначения. Это обозначение, которое вы используете, когда пишете !flag
или val liability = -debt
.
Инфикс:
Это обозначение, в котором метод появляется между объектом и его параметрами. Здесь подходят все арифметические операторы.
Постфикс (также суффикс):
Эта запись используется, когда метод следует за объектом и не получает параметров . Например, вы можете писать list tail
, и это постфиксная запись.
Вы можете без проблем связать вызовы инфиксной нотации, пока не будет каррирован какой-либо метод. Например, мне нравится использовать следующий стиль:
(list
filter (...)
map (...)
mkString ", "
)
Это то же самое, что:
list filter (...) map (...) mkString ", "
Теперь, почему я использую здесь круглые скобки, если filter и map принимают один параметр? Это потому, что я передаю им анонимные функции. Я не могу смешивать определения анонимных функций с инфиксным стилем, потому что мне нужна граница для конца моей анонимной функции. Кроме того, определение параметра анонимной функции может интерпретироваться как последний параметр инфиксного метода.
Вы можете использовать инфикс с несколькими параметрами:
string substring (start, end) map (_ toInt) mkString ("<", ", ", ">")
Каррированные функции сложно использовать с инфиксной нотацией. Функции сворачивания являются ярким примером этого:
(0 /: list) ((cnt, string) => cnt + string.size)
(list foldLeft 0) ((cnt, string) => cnt + string.size)
Вам необходимо использовать круглые скобки вне вызова инфикса. Я не уверен, что здесь действуют точные правила.
Теперь поговорим о постфиксе. Postfix может быть трудным в использовании, потому что его нельзя использовать нигде, кроме конца выражения . Например, нельзя делать следующее:
list tail map (...)
Потому что хвост не появляется в конце выражения. Вы тоже не можете этого сделать:
list tail length
Вы можете использовать инфиксную нотацию, используя круглые скобки для обозначения конца выражений:
(list tail) map (...)
(list tail) length
Обратите внимание, что постфиксная нотация не рекомендуется, потому что она может быть небезопасной .
Надеюсь, это развеяло все сомнения. Если нет, просто оставьте комментарий, и я посмотрю, что я могу сделать, чтобы его улучшить.
Определения классов:
val
илиvar
может быть опущено в параметрах класса, что сделает параметр закрытым.Добавление var или val приведет к тому, что он станет общедоступным (то есть будут созданы методы доступа и мутаторы).
{}
может быть опущено, если у класса нет тела, то естьСоздание экземпляра класса:
Общие параметры можно не указывать, если они могут быть определены компилятором. Однако обратите внимание: если ваши типы не совпадают, параметр типа всегда передается, чтобы он соответствовал. Таким образом, без указания типа вы можете не получить то, что ожидаете, то есть с учетом
Это даст вам ошибку типа (найден Int, ожидаемая строка)
Тогда как это отлично работает:
Поскольку параметр типа T определяется как наименее распространенный супертип из двух - Any.
Определения функций:
=
может быть отброшен, если функция возвращает Unit (ничего).{}
для тела функции можно отбросить, если функция является одним оператором, но только если оператор возвращает значение (вам нужен=
знак), то естьно это не работает:
Тип возвращаемого значения функции можно не указывать, если его можно вывести (рекурсивный метод должен иметь указанный тип возврата).
()
можно отбросить, если функция не принимает аргументов, то естькоторый по соглашению зарезервирован для методов, не имеющих побочных эффектов - подробнее об этом позже.
()
на самом деле не отбрасывается как таковой при определении параметра передачи по имени , но на самом деле это совершенно семантически другая нотация, то естьГоворит, что myOp принимает параметр передачи по имени, который приводит к строке (то есть это может быть блок кода, который возвращает строку), а не параметры функции,
в котором говорится, что
myOp
принимает функцию с нулевыми параметрами и возвращает строку.(Имейте в виду, что параметры, передаваемые по имени, компилируются в функции; это просто улучшает синтаксис.)
()
может быть опущено в определении параметра функции, если функция принимает только один аргумент, например:Но если требуется более одного аргумента, вы должны включить ():
Заявления:
.
можно отбросить, чтобы использовать нотацию операторов, которая может использоваться только для инфиксных операторов (операторов методов, принимающих аргументы). См . Ответ Даниэля для получения дополнительной информации..
также может быть удалено для хвоста списка постфиксных функций()
можно отбросить для постфиксных операторов list.tail()
не может использоваться с методами, определенными как:Поскольку эта нотация зарезервирована по соглашению для методов, которые не имеют побочных эффектов, таких как List # tail (то есть вызов функции без побочных эффектов означает, что функция не имеет наблюдаемого эффекта, за исключением ее возвращаемого значения).
()
можно опустить для обозначения оператора при передаче одного аргумента()
может потребоваться использовать постфиксные операторы, которых нет в конце оператора()
может потребоваться для обозначения вложенных операторов, концов анонимных функций или для операторов, которые принимают более одного параметраПри вызове функции, которая принимает функцию, вы не можете опустить () из определения внутренней функции, например:
При вызове функции, которая принимает параметр по имени, вы не можете указать аргумент как анонимную функцию без параметров. Например, учитывая:
Вы должны называть это так:
или
но нет:
ИМО, чрезмерное использование отбрасываемых типов возврата может быть вредным для повторного использования кода. Просто посмотрите на спецификацию, чтобы увидеть хороший пример снижения читабельности из-за отсутствия явной информации в коде. Количество уровней косвенного обращения к типу переменной может быть безумным. Надеюсь, более совершенные инструменты помогут избежать этой проблемы и сделать наш код лаконичным.
(Хорошо, в стремлении составить более полный, краткий ответ (если я что-то пропустил или получил что-то не так / неточно, прокомментируйте), я добавил в начало ответа. Обратите внимание, что это не язык спецификации, поэтому я не пытаюсь сделать ее строго академически правильной - просто больше похоже на справочную карту.)
источник
Коллекция цитат, дающих представление о различных условиях ...
Лично я думал, что в спецификации будет больше. Я уверен, что должно быть, я просто не ищу нужных слов ...
Однако есть несколько источников, и я собрал их вместе, но ничего по-настоящему полного / исчерпывающего / понятного /, которое объясняет мне вышеуказанные проблемы ...:
Из главы 2 «Печатай меньше, делай больше» Programming Scala :
Из главы 1 « От нуля до шестидесяти: введение в Scala» Programming Scala :
Из сообщения в блоге Scala Syntax Primer :
Из спецификации языка:
Из Scala для Java Refugees, часть 6: Преодоление Java :
Какие символы я могу опустить в Scala?
Но еще меня смущает эта цитата:
Потому что, насколько я могу видеть, есть это объект , чтобы принять вызов ...
источник
Мне легче следовать этому практическому правилу: в выражениях пробелы чередуются между методами и параметрами. В вашем примере
(service.findAllPresentations.get.first.votes.size) must be equalTo(2)
анализируется как(service.findAllPresentations.get.first.votes.size).must(be)(equalTo(2))
. Обратите внимание, что круглые скобки вокруг 2 имеют более высокую ассоциативность, чем пробелы. Точки также имеют более высокую ассоциативность, поэтому(service.findAllPresentations.get.first.votes.size) must be.equalTo(2)
будут разбираться как(service.findAllPresentations.get.first.votes.size).must(be.equalTo(2))
.service findAllPresentations get first votes size must be equalTo 2
разбирается какservice.findAllPresentations(get).first(votes).size(must).be(equalTo).2
.источник
На самом деле, при втором чтении, возможно, это ключ:
Как упоминалось в сообщении блога: http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-6 .
Так что, возможно, это на самом деле очень строгий «синтаксический сахар», который работает только тогда, когда вы эффективно вызываете метод для объекта, который принимает один параметр . например
И ничего больше.
Это объяснило бы мои примеры в вопросе.
Но, как я уже сказал, был бы очень признателен, если бы кто-то мог указать, где именно в спецификации языка это указано.
Хорошо, какой-то приятный парень (paulp_ из #scala) указал, где в спецификации языка эта информация:
Хм - для меня это не согласуется с тем, что я вижу, или я просто этого не понимаю;)
источник
Нет ни одного. Скорее всего, вы получите совет о том, есть ли у этой функции побочные эффекты. Это подделка. Исправление состоит в том, чтобы не использовать побочные эффекты в разумных пределах, допускаемых Scala. В той степени, в которой это невозможно, все ставки отключены. Все ставки. Использование круглых скобок является элементом набора «все» и является лишним. После отмены всех ставок он не дает никакой ценности.
Этот совет, по сути, является неудачной попыткой создать систему эффектов (не путать с: менее полезен, чем другие системы эффектов).
Старайтесь не вызывать побочных эффектов. После этого подтвердите, что все ставки отключены. Скрытие за фактической синтаксической нотацией для системы эффектов может и приносит только вред.
источник