Что за магия стоит за $ (($ i ++))? - PullRequest
4 голосов
/ 16 июня 2019

Вот небольшой фрагмент кода, который выводит 1 2 3 ... с интервалом в 1 секунду.

while ($true) {
  sleep -s 1
  "$(($i++))"
}

Как это возможно?

Ответы [ 2 ]

10 голосов
/ 16 июня 2019

В комментариях есть хорошие указатели, но позвольте мне копнуть немного глубже:

Объяснение $i++:

  • $i++ использует ++, оператор приращения , чтобы увеличить значение переменной $i на 1, что может быть знакомо по таким языкам, как C # и C / C ++,Как и ожидалось, существует дополнительный декремент оператор --)

    • Поскольку ++ позиционируется после переменной( postfix form), увеличение происходит после значение переменной было использовано в выражении;поместив его перед , переменная - ++$i ( prefix form) будет выполнять приращение first ;если операция увеличения / уменьшения используется отдельно, это различие не имеет значения. Предполагается, что

    • $i содержит экземпляр типа numeric , в противном случаевозникает ошибка;если переменная $i не была инициализирована, ее значение равно $null, что в PowerShell приводит к [int] -типу 0.Таким образом, $i++ оценивается до 0 в контексте его оператора и впоследствии увеличивается до 1.

  • увеличение / уменьшениевыражение, такое как $i++, обрабатывается как назначение - вы можете думать о нем как $i = $i + 1 - а назначения в PowerShell не производят вывод (они ничего не возвращают; они только обновляют значение переменной).

Объяснение (...) вокруг $i++:

  • Byзаключая назначение в скобки ((...)) , вы превращаете его в выражение , что означает, что значение назначенияпередано от до , чтобы оно могло участвовать в большем выражении;Например:
    • $i = 0 ... без вывода - просто присваивает значение 0 переменной $i.
    • ($i = 1) ... выводит 1: из-за (...) назначенное значение также выводится.
    • (++$i) ... предварительное увеличение: увеличивает значение от $i до 2 и выводит это значение.
    • ($i++) ... после декремента: выводит 2, текущее значение, , затем увеличивает значение до 3.

Объяснение $(...) вокруг ($i++):

  • $(...), оператор подвыражения , необходим для встраивания вывода одного или нескольких операторов в контексты, где операторы не поддерживаются напрямую.В частности, вы можете использовать его для встраивания вывода команды в расширяемую строку ("..."), т. Е. Для интерполяции строки .

    • Обратите внимание, что $(...) требуется только для встраивания выражений (например, что-то, заключенное в (...), доступа к свойству ($foo.bar), индексации (($foo[0])) и вызовов методов ($foo.Baz())) и команды (например, Get-Date), а не только для ссылок на переменные, таких как "Honey, I'm $HOME".См. этот ответ для получения дополнительной информации о расширяемых строках в PowerShell.
  • Хотя в вашем простом примере нет строгой необходимости в расширяемой строке - просто ($i++) будет производить вывод, который выглядит одинаково [1] - $(...) полезен для создания значения ($i++) частью большей строки;например, "Iteration #$(($i++))" для печати "Iteration #0", "Iteration #1", ...


[1] ($i++) - это число , тогда как "$(($i++)" - это строка , где преобразование числа в строку произошло как часть интерполяции строки.Хотя это обычно приводит к одному и тому же выводу на консоль, оно может фактически отличаться для нецелых чисел, таких как 1.2, поскольку прямой вывод применяется с учетом culture строковое преобразование, тогда как строковая интерполяция является инвариантом культуры 1187 *.Таким образом, с действующей культурой, которая использует , в качестве десятичной метки -eg, fr-FR, 1.2 печатает - соответственно, культурно - как 1,2 на консоли, тогда как "$(1.2)" всегда печатается как 1.2

0 голосов
/ 17 июня 2019

В powershell присваивания также являются выражениями.Но вывод выражений обычно не отображается.Потому что все, что выводится внутри функции, будет возвращено ей.

PS C:\users\js> $a = ($b = 1)
PS C:\users\js> $a
1
PS C:\users\js> $b
1    

Кстати, $ () не только для внутренних строк.Вы можете поместить в него несколько операторов, разделенных точками с запятой, и использовать ключевые слова, такие как foreach и if, а затем поместить их в любое место, где можно поместить выражение (конвейер).

PS C:\users\js> $(if ($true) { echo hi }; echo there) | measure


Count    : 2
Average  :
Sum      :
Maximum  :
Minimum  :
Property :
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...