Искра: разница с использованием map () и map {} [duplicate]

Мне очень нравится, как Wordpress работает с его функциями enqueue и localize , поэтому после этой модели я написал простой класс для размещения скриптов на странице в соответствии с зависимостей сценария и получения дополнительных данных для скрипта.

class mHeader {

    private $scripts = array();

    /**
     * @param string $id        unique script identifier
     * @param string $src   script src attribute
     * @param array  $deps      an array of dependencies ( script identifiers ).
     * @param array  $data      an array, data that will be json_encoded and available to the script.
     */
    function enqueue_script( $id, $src, $deps = array(), $data = array() ) {
        $this->scripts[$id] = array( 'src' => $src, 'deps' => $deps, 'data' => $data );
    }

    private function dependencies( $script ) {
        if ( $script['deps'] ) {
            return array_map( array( $this, 'dependencies' ), array_intersect_key( $this->scripts, array_flip( $script['deps'] ) ) );
        }
    }

    private function _unset( $key, &$deps, &$out ) {
        $out[$key] = $this->scripts[$key];
        unset( $deps[$key] );
    }

    private function flattern( &$deps, &$out = array() ) {

        foreach( $deps as $key => $value ) {            
            empty($value) ? $this->_unset( $key, $deps, $out ) : $this->flattern( $deps[$key], $out );
        }
    }   

    function print_scripts() {

        if ( !$this->scripts ) return;

        $deps = array_map( array( $this, 'dependencies' ), $this->scripts );
        while ( $deps ) 
            $this->flattern( $deps, $js );

        foreach( $js as $key => $script ) {
            $script['data'] && printf( "" . PHP_EOL, key( $script['data'] ), json_encode( current( $script['data'] ) ) );
            echo "" . PHP_EOL;
        }
    }
}

Функция enqueue_script() предназначена для добавления сценария, установки сума и зависимостей в других сценариях и дополнительных данных, необходимых для скрипт.

$header = new mHeader();

$header->enqueue_script( 'jquery-ui', '//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js', array( 'jquery' ) );
$header->enqueue_script( 'jquery', '//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js' );
$header->enqueue_script( 'custom-script', '//custom-script.min.js', array( 'jquery-ui' ), array( 'mydata' => array( 'value' => 20 ) ) );

$header->print_scripts();

И, метод print_scripts() вышеприведенного примера отправит этот вывод:





Независимо от того, что скрипт jquery находится в очереди после 'jquery-ui', он печатается ранее, потому что он определен в 'jquery-ui', который зависит от `jquery '. Дополнительные данные для «custom-script» находятся внутри нового блока сценариев и размещаются перед ним, он содержит mydata объект, который содержит дополнительные данные, теперь доступный для «пользовательского сценария».

277
задан Peter Mortensen 1 May 2013 в 21:41
поделиться

8 ответов

Я попробовал раз писать об этом, но в конце концов я сдался, так как правила несколько размыты. В принципе, вам придется повесить его.

Возможно, лучше сосредоточиться на том, где фигурные скобки и скобки могут использоваться взаимозаменяемо: при передаче параметров вызовам метода. Вы можете заменить скобку фигурными скобками, если и только если метод ожидает единственный параметр. Например:

List(1, 2, 3).reduceLeft{_ + _} // valid, single Function2[Int,Int] parameter

List{1, 2, 3}.reduceLeft(_ + _) // invalid, A* vararg parameter

Тем не менее, вам нужно больше знать, чтобы лучше понять эти правила.

Расширенная проверка компиляции с помощью parens

Авторы Spray рекомендуйте круглые парсеры, потому что они дают повышенную проверку компиляции. Это особенно важно для DSL, таких как Spray. Используя parens, вы сообщаете компилятору, что ему должна быть предоставлена ​​только одна строка; поэтому, если вы случайно дадите ему два или более, он будет жаловаться. Теперь это не так с фигурными фигурными скобками - если, например, вы где-то забыли оператор, тогда ваш код будет компилироваться, и вы получите неожиданные результаты и потенциально очень сложную ошибку. Ниже изобретено (так как выражения чисты и, по крайней мере, дают предупреждение), но делает точку:

method {
  1 +
  2
  3
}

method(
  1 +
  2
  3
)

Первые компиляции, вторая дает error: ')' expected but integer literal found. Автор хотел написать 1 + 2 + 3.

Можно утверждать, что это похоже на многопараметрические методы с аргументами по умолчанию; невозможно случайно забыть запятую, чтобы отделять параметры при использовании парнеров.

Многозначность

Важное часто забытое примечание о многословии. Использование фигурных скобок неизбежно приводит к подробному коду, поскольку руководство стиля Scala четко заявляет, что закрытие фигурных скобок должно быть в их собственной строке:

... закрывающая фигурная скобка находится на ее собственной строки сразу после последней строки функции.

Многие автореформаторы, как и в IntelliJ, автоматически выполнит эту переформатировку для вас. Так что старайтесь использовать круглые паренны, когда сможете.

Инфиксная нотация

При использовании инфиксной нотации, например List(1,2,3) indexOf (2), вы можете опустить скобки, если есть только один параметр и записать его как List(1, 2, 3) indexOf 2. Это не относится к точечной нотации.

Обратите также внимание, что если у вас есть один параметр, который является выражением с несколькими токенами, например x + 2 или a => a % 2 == 0, вы должны использовать скобки для указания границы выражения.

Кортежи

Поскольку вы иногда можете опускать скобки, иногда кортеж нуждается в дополнительных скобках, например, в ((1, 2)), а иногда внешняя скобка может быть опущена, например в (1, 2). Это может вызвать путаницу.

Функциональные / частичные литералы функции с case

Scala имеет синтаксис для литералов функций и частичных функций. Это выглядит так:

{
    case pattern if guard => statements
    case pattern => statements
}

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

object match {
    case pattern if guard => statements
    case pattern => statements
}
try {
    block
} catch {
    case pattern if guard => statements
    case pattern => statements
} finally {
    block
}

Вы не можете использовать выражения case в любом другом контексте . Итак, если вы хотите использовать case, вам нужны фигурные скобки . В случае, если вам интересно, что делает различие между функцией и литералом частичной функции, ответ таков: контекст. Если Scala ожидает функцию, вы получите функцию. Если он ожидает частичную функцию, вы получаете частичную функцию. Если оба они ожидаются, это дает ошибку в двусмысленности.

Выражения и блоки

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

{
    import stuff._
    statement ; // ; optional at the end of the line
    statement ; statement // not optional here
    var x = 0 // declaration
    while (x < 10) { x += 1 } // stuff
    (x % 5) + 1 // expression
}

( expression )

Итак, если вам нужны декларации, несколько операторов, import или что-то в этом роде, вам нужны фигурные скобки. И поскольку выражение является выражением, скобки могут появляться внутри фигурных скобок. Но интересно то, что блоками кода являются выражения также , поэтому вы можете использовать их где угодно внутри выражение:

( { var x = 0; while (x < 10) { x += 1}; x } % 5) + 1

Итак, поскольку выражения - это выражения, а блоки кодов - выражения, все ниже:

1       // literal
(1)     // expression
{1}     // block of code
({1})   // expression with a block of code
{(1)}   // block of code with an expression
({(1)}) // you get the drift...

Где они не взаимозаменяемы

В принципе, вы не можете заменить {} на () или наоборот в другом месте. Например:

while (x < 10) { x += 1 }

Это не вызов метода, поэтому вы не можете записать его каким-либо другим способом. Ну, вы можете поместить фигурные скобки внутри в скобки для condition, а также использовать скобки внутри фигурные скобки для блока кода:

while ({x < 10}) { (x += 1) }

Итак, я надеюсь, что это поможет.

311
ответ дан Mario Galic 21 August 2018 в 20:45
поделиться
  • 1
    Вот почему люди утверждают, что Скала сложна. Я бы назвал себя энтузиастом Scala. – andyczerwonka 7 November 2012 в 22:46

Поскольку вы используете case, вы определяете частичную функцию, а частичные функции требуют фигурных скобок.

6
ответ дан fjdumont 21 August 2018 в 20:45
поделиться
  • 1
    Я попросил ответа в целом, а не просто ответ на этот пример. – Marc-François 22 August 2012 в 15:20

Я не думаю, что в Scala есть что-то особенное или сложное в фигурных скобках. Чтобы справиться с кажущимся сложным использованием их в Scala, просто сохраните пару простых вещей:

  1. фигурные скобки образуют блок кода, который оценивает последнюю строку кода (почти все языки делают это)
  2. функция, если требуется, может быть сгенерирована блоком кода (следует правилу 1)
  3. фигурные скобки могут быть опущены для однострочного кода, за исключением случая (выбор Scala)
  4. круглые скобки могут быть опущены при вызове функции с кодовым блоком в качестве параметра (выбор Scala)

Давайте объясним несколько примеров в трех предыдущих правила:

val tupleList = List[(String, String)]()
// doesn't compile, violates case clause requirement
val filtered = tupleList.takeWhile( case (s1, s2) => s1 == s2 ) 
// block of code as a partial function and parentheses omission,
// i.e. tupleList.takeWhile({ case (s1, s2) => s1 == s2 })
val filtered = tupleList.takeWhile{ case (s1, s2) => s1 == s2 }

// curly braces omission, i.e. List(1, 2, 3).reduceLeft({_+_})
List(1, 2, 3).reduceLeft(_+_)
// parentheses omission, i.e. List(1, 2, 3).reduceLeft({_+_})
List(1, 2, 3).reduceLeft{_+_}
// not both though it compiles, because meaning totally changes due to precedence
List(1, 2, 3).reduceLeft _+_ // res1: String => String = <function1>

// curly braces omission, i.e. List(1, 2, 3).foldLeft(0)({_ + _})
List(1, 2, 3).foldLeft(0)(_ + _)
// parentheses omission, i.e. List(1, 2, 3).foldLeft(0)({_ + _})
List(1, 2, 3).foldLeft(0){_ + _}
// block of code and parentheses omission
List(1, 2, 3).foldLeft {0} {_ + _}
// not both though it compiles, because meaning totally changes due to precedence
List(1, 2, 3).foldLeft(0) _ + _
// error: ';' expected but integer literal found.
List(1, 2, 3).foldLeft 0 (_ + _)

def foo(f: Int => Unit) = { println("Entering foo"); f(4) }
// block of code that just evaluates to a value of a function, and parentheses omission
// i.e. foo({ println("Hey"); x => println(x) })
foo { println("Hey"); x => println(x) }

// parentheses omission, i.e. f({x})
def f(x: Int): Int = f {x}
// error: missing arguments for method f
def f(x: Int): Int = f x
12
ответ дан lcn 21 August 2018 в 20:45
поделиться
  • 1
    1. на самом деле не соответствует действительности на всех языках. 4. на самом деле не верно в Scala. Например: def f (x: Int) = f x – aij 24 September 2015 в 17:47
  • 2
    @aij, спасибо за комментарий. Для 1 я предлагал знакомое, что Scala обеспечивает поведение {}. Я обновил формулировку для точности. И для 4, это немного сложно из-за взаимодействия между () и {}, поскольку def f(x: Int): Int = f {x} работает, и именно поэтому у меня был пятый. :) – lcn 24 September 2015 в 20:18
  • 3
    Я склонен думать о () и {} как основном взаимозаменяемом в Scala, за исключением того, что он анализирует содержимое по-разному. Обычно я не пишу f ({x}), так что f {x} не хочет пропускать круглые скобки так же, как заменять их на curlies. Другие языки действительно позволяют вам пропустить парекеты. Например, fun f(x) = f x действителен в SML. – aij 26 September 2015 в 14:34
  • 4
    @aij, рассматривая f {x} как f({x}), для меня лучше, чем объяснение , поскольку взаимозаменяемость мышления () и {} менее интуитивная. Кстати, интерпретация f({x}) несколько подкреплена спецификацией Scala (раздел 6.6): ArgumentExprs ::= ‘(’ [Exprs] ‘)’ | ‘(’ [Exprs ‘,’] PostfixExpr ‘:’ ‘_’ ‘*’ ’)’ | [nl] BlockExp – lcn 27 September 2015 в 02:45

Я думаю, что стоит объяснить их использование в вызовах функций и почему происходят разные вещи. Поскольку кто-то уже сказал, что фигурные скобки определяют блок кода, который также является выражением, поэтому можно поставить выражение, в котором ожидается выражение, и оно будет оценено. Когда оценивается, его операторы выполняются, а значение последнего оператора - результат оценки целочисленного блока (несколько как в Ruby).

Имея это, мы можем делать такие вещи, как:

2 + { 3 }             // res: Int = 5
val x = { 4 }         // res: x: Int = 4
List({1},{2},{3})     // res: List[Int] = List(1,2,3)

Последний пример - это просто вызов функции с тремя параметрами, каждый из которых сначала оценивается.

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

def foo(f: Int => Unit) = { println("Entering foo"); f(4) }

Чтобы вызвать ее, нам нужно передать функцию, которая принимает один param из типа Int, поэтому мы можем использовать функциональный литерал и передать его foo:

foo( x => println(x) )

Теперь, как сказано ранее, мы можем использовать блок кода вместо выражения, поэтому давайте использовать его

foo({ x => println(x) })

Что здесь происходит, так это то, что код внутри {} оценивается, а значение функции возвращается как значение оценки блока, это значение затем передается в foo. Это семантически то же самое, что и предыдущий вызов.

Но мы можем добавить что-то еще:

foo({ println("Hey"); x => println(x) })

Теперь наш блок кода содержит два оператора и потому, что он вычисляется до выполнения foo , происходит то, что сначала печатается «Эй», затем наша функция передается в foo, «Ввод foo» печатается и, наконец, печатается «4».

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

foo { println("Hey"); x => println(x) }

или

foo { x => println(x) }

Это выглядит намного приятнее и эквивалентно предыдущим. Здесь сначала вычисляется блок кода, и результат оценки (который является x => println (x)) передается как аргумент для foo.

13
ответ дан Lukasz Korzybski 21 August 2018 в 20:45
поделиться
  • 1
    Это только я. но я действительно предпочитаю явный характер foo({ x => println(x) }). Может быть, я слишком застрял на своих путях ... – dade 12 May 2016 в 01:04

У сообщества есть возможность стандартизировать использование фигурных скобок и круглых скобок, см. Руководство по стилю Scala (стр. 21): http://www.codecommit.com/scala-style-guide.pdf

Рекомендуемый синтаксис вызовов методов более высокого порядка состоит в том, чтобы всегда использовать фигурные скобки и пропускать точку:

val filtered = tupleList takeWhile { case (s1, s2) => s1 == s2 }

Для «нормальных» вызовов методам вы должны использовать точку и круглые скобки.

val result = myInstance.foo(5, "Hello")
21
ответ дан om-nom-nom 21 August 2018 в 20:45
поделиться
  • 1
    На самом деле конвенция заключается в использовании круглых фигурных скобок, эта ссылка не является официальной. Это связано с тем, что в функциональном программировании все функции являются просто гражданами первого порядка, и поэтому НЕ следует относиться по-разному. Во-вторых, Мартин Одерски говорит, что вы должны пытаться использовать только инфикс для подобных операторов (например, +, --), а не обычные методы, такие как takeWhile. Вся нотация инфикс заключается в том, чтобы разрешить DSL и пользовательские операторы, поэтому их следует использовать в этом контексте не все время. – samthebest 29 December 2014 в 09:51

Повышенная проверка компиляции с помощью parens

Авторы Spray рекомендуют, чтобы круглые парсеры увеличивали проверку компиляции. Это особенно важно для DSL, таких как Spray. Используя parens, вы сообщаете компилятору, что ему должна быть предоставлена ​​только одна строка, поэтому, если вы случайно дали ей два или более, она будет жаловаться. Теперь это не так с фигурными фигурными скобками, если, например, вы забудете оператора где-нибудь, где ваш код будет скомпилирован, вы получите неожиданные результаты и потенциально очень сложную ошибку. Ниже изобретено (так как выражения чисты и будут хотя бы давать предупреждение), но делает точку

method {
  1 +
  2
  3
}

method(
  1 +
  2
  3
 )

Первые компиляции, вторая дает error: ')' expected but integer literal found., которую автор хотел написать 1 + 2 + 3 .

Можно утверждать, что это похоже на многопараметрические методы с аргументами по умолчанию; невозможно случайно забыть запятую, чтобы отделять параметры при использовании парсеров.

Многозначность

Важное часто забытое примечание о многословии. Использование фигурных скобок неизбежно приводит к подробному коду, поскольку в руководстве по стилю скалы четко указано, что закрытие фигурных скобок должно быть в их собственной строке: http://docs.scala-lang.org/style/declarations.html «... закрывающая скобка находится на собственной линии сразу после последней строки функции». Многие автореформаторы, как и в Intellij, автоматически выполнит эту переформатировку для вас. Поэтому старайтесь использовать круглые парнеры, когда сможете. Например. List(1, 2, 3).reduceLeft{_ + _} становится:

List(1, 2, 3).reduceLeft {
  _ + _
}
4
ответ дан samthebest 21 August 2018 в 20:45
поделиться

С фигурными скобками у вас есть точка с запятой, вызванная для вас, а в скобках нет. Рассмотрим функцию takeWhile, так как она ожидает частичную функцию, только {case xxx => ??? } является корректным определением вместо круглых скобок вокруг выражения case.

-3
ответ дан Shobi P P 21 August 2018 в 20:45
поделиться

Существует несколько различных правил и выводов: во-первых, Scala выводит фигурные скобки, когда параметр является функцией, например. в list.map(_ * 2) выводятся фигурные скобки, это всего лишь более короткая форма list.map({_ * 2}). Во-вторых, Scala позволяет пропустить скобки в последнем списке параметров, если в списке параметров есть один параметр, и это функция, поэтому list.foldLeft(0)(_ + _) можно записать как list.foldLeft(0) { _ + _ } (или list.foldLeft(0)({_ + _}), если вы хотите быть дополнительным явным).

Однако, если вы добавите case, вы получите, как указывали другие, частичную функцию вместо функции, а Scala не будет выводить фигурные скобки для частичных функций, поэтому list.map(case x => x * 2) выиграл 't работают, но оба list.map({case x => 2 * 2}) и list.map { case x => x * 2 } будут.

52
ответ дан Theo 21 August 2018 в 20:45
поделиться
  • 1
    Не только последний список параметров. Например, list.foldLeft{0}{_+_} работает. – Daniel C. Sobral 8 December 2010 в 12:28
  • 2
    Ах, я был уверен, что прочитал, что это только последний список параметров, но я явно ошибся! Хорошо знать. – Theo 8 December 2010 в 13:55
Другие вопросы по тегам:

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