引用全局变量时使用$global:scope前缀是可选的吗



如果我用$global:MyVariable = "123"声明并初始化PowerShell变量,那么我需要在使用该变量的任何地方使用$global:还是只使用$MyVariable?

  • 原则上可以仅使用$MyVariable引用该名称的全局变量的值,但您可能会在不同情况下看到不同变量的值。

  • 具体地说,如果任何介入的祖先(父)作用域,甚至调用作用域本身也创建了一个$MyVariable变量(通常通过简单的赋值隐式地发生;例如$MyVariable = ...),您将看到变量的值。

  • 如果使用全局作用域说明符,即:$global:MyVariable(或Get-Variable -ValueOnly -Scope Global MyVariable)[1],则只有保证才能看到全局值

  • 默认情况下,变量可见,但在所有子(子)作用域中不能直接可修改

    • 因此必须使用$global:MyVariable/Set-Variable -Scope Global才能修改(设置)全局变量;如果没有$global:,您将隐式创建一个同名的本地变量
    • 有关PowerShell作用域规则的更多信息,请参阅此答案的最后一部分

[1]在现实场景中,即使PowerShell模块中的代码也会看到具有范围说明符$global:的全局变量,并且全局变量的隐式可见性始终适用。

对于内存模块,有一种方法可以使$global/-Scope global引用一个不同的范围,即模块自己的顶级范围,但该技术尚不明确,没有文档记录,其实际用途未知
如果您想了解更多信息,请继续阅读。


可选读取:创建一个将自己的顶级作用域视为全局作用域的内存模块:

PetSerAl发现了一种鲜为人知的方法来创建内存模块,使其将$global:/-Scope global视为其自己的顶级作用域,而不是真正的全局作用域-奇怪的是,而不是使用显式作用域引用使代码仍然可以看到(无阴影)全局变量:

$global:MyVariable = 42 # Create a true global variable.
# Create an in-memory module for which its *own top-level scope*
# becomes the "global" scope, by virtue of passing $false to the
# [psmoduleinfo] constructor:
& ([psmoduleinfo]::new($false)) {
@"
"$global:MyVariable",
"$(Get-Variable -ValueOnly -Scope global MyVariable)",
"$MyVariable"
"@
}

收益率:

Get-Variable : Cannot find a variable with the name 'MyVariable'.
# ...
"",  # $global:MyVariable didn't find the variable
",   # Neither did Get-Variable -Scope Global (see error above)
"42" # OK - implicit visibility of true global variables

请注意,New-ModuleImport-Module(对于持久化模块)都不提供此功能。

Patrick Meinecke在这篇优秀的博客文章中解释了上面用于调用模块范围内的脚本块的晦涩的& <module-info> { ... }技术。

运行这个程序,看看最好总是指定,如果你不指定,你就不会总是得到你可能期望的

function func {
"0. $myvar"
$myvar='funclocal'
"1. $myvar"
"2. $Global:myvar"
}
$Global:myvar='global'
func
"3. $Global:myvar"

调用时不需要使用$global:

最新更新