Вопрос по scope, result, private, powershell – «Приватная» сфера Powershell, кажется, вообще бесполезна

5

У меня есть сценарий ниже, из Интернета:

$private:a = 1
Function test  {
    "variable a contains $a"
    $a = 2
    "variable a contains $a"
}
test

Он печатает 2. Нет проблем. Если я удалю «личное», как показано ниже:

$a = 1
Function test  {
    "variable a contains $a"
    $a = 2
    "variable a contains $a"
}

Тем не менее он печатает «2». Кажется без разницы. Не могли бы вы дать краткий пример того, как «частная» сфера влияет на результат?

Благодарю.

Ваш Ответ

3   ответа
-1

ь (между прочим). В рамках Powershell это включает использование частного ПО КАЖДОМУ ПЕРЕМЕННОМУ, ЧТО ВЫ МОЖЕТЕ. Если вы хотите сделать значение доступным в некотором впоследствии названном модуле, передайте эту информацию ЯВНО. Должна быть очень веская ИСКЛЮЧИТЕЛЬНАЯ причина для того, чтобы этого не делать, потому что каждый раз, когда вы полагаетесь на неявное знание (например, то, что происходит в Powershell, когда вы не используете частные переменные), вы увеличиваете вероятность того, что что-то неожиданно пойдет не так позже ( возможно, месяцы спустя, когда в программном обеспечении будет гораздо больше кода).

Хорошая рекомендация, но это означает, что всегда нужно быть явным при создании ($private:var = ...  вместо$var = ...). Кроме того, учитывая, что вопрос заключается в том, как работает частная сфера, а не в том, стоит ли ее использовать, целесообразно соответствующим образом сформулировать ваш ответ. mklement0
10

которая вызывает предоставленный пользователем обратный вызов. Рассмотрим этот простой пример:

filter Where-Name {
    param(
        [ScriptBlock]$Condition
    )
    $FirstName, $LastName = $_ -split ' '
    if(&$Condition $FirstName $LastName) {
        $_
    }
}

Затем, если кто-то называет это так:

$FirstName = 'First2'
'First1 Last1', 'First2 Last2', 'First3 Last3' |
  Where-Name {param($a, $b) $a -eq $FirstName}

они ожидают увидеть толькоFirst2 Last2 строка, но на самом деле это напечатает все три строки. Это из-за столкновения на$FirstName переменная. Чтобы предотвратить такие столкновения, вы можете объявить переменные вWhere-Name как личное:

filter Where-Name {
    param(
        [ScriptBlock]$private:Condition
    )
    $private:FirstName, $private:LastName = $_ -split ' '
    if(&$Condition $FirstName $LastName) {
        $_
    }
}

Сейчас$FirstName вWhere-Name не скрывает$FirstName во внешней области при ссылке из$Condition блок скриптов.

@ mklement0 У меня все работает как есть: без добавленияprivate: когда я ссылаюсь$Condition внутри функции тела. PetSerAl
@ mklement0 Для меня это выглядит как ошибка в v5 (на самом деле угадать это, начиная с v3, ИМХО, это ошибка оптимизации DLR). В v2 это распечататьhi и если я напишу это так:function foo([ScriptBlock] $private:sb) { & $sb; if($false){$private:sb} }; $sb = 'hi'; foo { $sb } - это печатьhi в v5. PetSerAl
@ mklement0$a=1; &{$a;$a+=2;$a;(gv a).GetType().FullName}; '-'; &{$a;$a+=2;$a;(gv a).GetType().FullName;if($false){rv}}; '-'; &{$a;$a+=2;$a;(gv a).GetType().FullName;rv a;$a}; '-'; sal x rv; &{$a;$a+=2;$a;(gv a).GetType().FullName;x a;$a} PetSerAl
Отличная идея использовать модули, спасибо за совет; в v3 + это даже можно сделатьдинамично: $null = New-Module { function foo([ScriptBlock] $sb) { & $sb } }; $sb = 'hi'; foo { $sb }, Кстати, кажется, что если вы хотите использовать$private: параметр в конце концов, вы должны продолжать использовать$private: когдапривязка этот параметр позже (переменные кажется, не имеют этого требования); т.е .:& $private:Condition .... mklement0
6

Замечания:
* Этот ответобъясняет почему код OP ведет себя так, как он (и что он ведет себя так, как задумано); Кроме того, он обеспечивает некоторыеобщая информация о переменных областях в PowerShell.
* Дляважное использование в реальном мире области видимостиprivate, увидетьПолезный ответ PetSerAl.

Ваш первый фрагмент кода:

variable a contains
variable a contains 2

Ваш второй отпечаток фрагмента:

variable a contains 1
variable a contains 2

В первом фрагменте, используя областьprivate вызывает родительскую (скриптовую) область видимостиa переменная бытьскрытый из дочерней (функциональной) области, как задумано, поэтому первая строка вывода показывает, что$a имеетнет значение
(неопределенная переменная имеет значение$null, который оценивает пустую строку в строковом контексте).

Во втором фрагменте, напротив, безprivate модификатор объема, переменнаяa из родительской области видимостивидимый в детской области.

В PowerShell функции выполняются вребенок Области применения по умолчанию.

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

Другими словами:

Назначение в$a в функции создаетФункция локального переменная с именем$aчто тогдатени (прячет)Сценарий уровня $a переменная (если она еще не была скрыта, будучи объявлена ​​как$private:a)Выходя из функции,$a снова имеет свое первоначальное значение уровня сценария.Общая информация о переменных областях в PowerShell

Если переменная явно не скрыта за областью действияprivate, потомок выходящий можетувидеть эта переменная а такжечитать его значение с использованием имени переменнойбез квалификатора области (например.,$a) или необходимостьGet-Variable -Scope.

Другие области не только не видят значения приватных переменных по умолчанию, но принципиально не могут ссылаться на них, даже при явном межобластном доступе с использованием модификаторов области илиGet-Variable -Scope.
(Втак же сфера, однако, выМожно использовать модификатор области для ссылки на приватную переменную, но только если этот модификатор области эффективно нацелен на ту же самую область, что всегда верно для$local:privateVarName, например).

Назначение для неквалифицированной переменной, однако, неявно создаетновый переменная вток (local) объем, которые могуттень переменная с тем же именем в наследственной области видимости.

Чтобы явно получить / изменить переменную в наследственной области, используйтеGet-Variable / Set-Variable -Scope <n> <name>, где<n> представляет уровень области, с0 представляющий текущую область,1 родительская область и так далее.
Обратите внимание, чтоGet-Variable возвращает[System.Management.Automation.PSVariable] экземпляр по умолчанию, поэтому для того, чтобы получить толькозначение, получить доступ к его.Value собственности, или используйте-ValueOnly переключатель, который только возвращает значение для начала.

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

([ref] $var).Value = ...(Если и когда локальная переменная с тем же именем будет создана, приведенное выше будет изменять толькоместный переменная, однако.)

Переменные вскрипт сфера иГлобальный объем можно также получить доступ - и изменить - с помощью$script: а также$global: модификаторы объема; например.,$script:a а также$global:a.
Обратите внимание, что$script: относится к (немедленно)вмещающий файл сценария сфера верхнего уровня.

Объявление переменной сSet-Variable -Option AllScope позволяет читатьи модифицированный влюбой потомок объембез необходимости уточнять имя; иначе говоря: тольконе замужем переменная с таким именем существует тогда, чтолюбая область видимости может напрямую читать и писать, используя неквалифицированное имя переменной.

Без отдельного-Scope параметр,-Option AllScope применяется к переменной вток область действия (например, область действия сценария на верхнем уровне сценария, локальная область действия функции внутри функции). Таким образом, чтобы безопасно создатьскрипт-глобальная переменная, к которой вы можете обращаться без разрешения для чтенияа также писать, использоватьSet-Variable -Scope Script -Option AllScope.

-Scope Global отличается от-Option AllScope: в то время как-Scope Global создает глобально доступную переменную, читая ееможети модифицируя егоделаеттребовать$global: модификатор объема. Также обратите внимание, чтоглобальная переменнаясессия-Глобальный, поэтому он сохраняется даже после завершения сценария, который определил его.

Объединяя-Scope Global с-Option AllScope вы эффективно создаетесессия- глобальная синглтон-переменная, которая может быть прочитана и записана из любой области видимости без спецификатора; как уже говорилось, такая переменная остается в силе даже после выхода из вашего скрипта.

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