Гуру Powershell, пожалуйста, уточните переменную область действия в функции - PullRequest
6 голосов
/ 02 апреля 2011

Я прочитал, что переменные внутри области функции доступны в текущей области, когда скрипт функции имеет точечный источник.

Это правда? Это очень странно и необычно, я думаю ...

Могу ли я уточнить причины этого? Например, my-f устанавливает $my-f-var в некоторое целое число, скажем, 2:

PS1> . .\my-f-script.ps1
PS1> my-f
PS1> $my-f-var
2

Я ожидаю, что $my-f-var недоступен, потому что внутри функции! Есть ли способ сделать переменные закрытыми или способ вызова функции без точечного поиска ее скрипта?

1 Ответ

14 голосов
/ 02 апреля 2011

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

PS> '$scriptvar = 2; function my-f { ${my-f-var} = 2 }' > my-f-script.ps1
PS> Remove-Variable scriptvar, my-f-var
Remove-Variable : Cannot find a variable with name 'scriptvar'.
Remove-Variable : Cannot find a variable with name 'my-f-var'.
PS> . .\my-f-script.ps1
PS> $scriptvar
2
PS> ${my-f-var}
PS>

Обратите внимание, что $ {my-f-var} не определенв местном масштабе.Однако, если я 'ставлю' точку 'на вызов функции, то ее содержимое запускается в текущей области видимости, например:

PS> . my-f
PS> ${my-f-var}
2

В этом случае переменная, установленная в функции, устанавливается в текущей (вызывая)область действия из-за 'точки', используемой для ее вызова.

Несколько других моментов: вы можете обращаться к переменным в различных областях, используя либо Get-Variable -scope, либо более удобный (если менее гибкий) глобальный, скрипт, локальныйи частные модификаторы.Когда вы обращаетесь к переменной внутри функции, где переменная определена в более высоком объеме, вы можете прочитать ее просто отлично.Но когда вы устанавливаете его, PowerShell, по сути, выполняет «копирование при записи» переменной - создавая новую копию, ограниченную этой функцией и далее (т. Е. Для других функций, которые она вызывает).Если вы действительно хотите изменить переменную с более высокой областью действия, вы можете использовать $ global: Foo или $ script: Foo для изменения этих областей.

Область local пригодится, если вы хотите избежать непреднамеренного использованияпеременная, определенная вне вашей функции.Другой MVP поднял этот вопрос на последнем саммите MVP, и это похоже на один из советов по «лучшей практике».Вот сценарий:

PS> $foo = 'bad'
PS> function testscope { $fooo = 'good'; "The value of `$fooo is $foo" }
PS> testscope
The value of $fooo is bad

Обратите внимание, что в этом случае использование $foo внутри функции является опечаткой, но по совпадению существует переменная с таким именем опечатки.Это не было целью функции, и она работает неправильно, хотя в этом случае это трудно увидеть.Ниже мы можем использовать спецификатор local, чтобы убедиться, что функция ищет переменную только в локальной области видимости.Он не находит его из-за опечатки, но, по крайней мере, ошибку теперь немного легче обнаружить.

PS> function testscope { $fooo = 'good'; "The value of `$fooo is $local:foo" }
PS> testscope
The value of $fooo is

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...