Powershell专家,请澄清函数中的变量范围

Emi*_*ggi 6 powershell scope

我读到当函数脚本是dot-sourced时,函数范围内的变量可以在当前作用域中访问.

这是真的吗?这很奇怪,我认为不寻常......

我可以澄清一下这个原因.例如,my-f设置$my-f-var为某个整数,假设为2:

PS1> . .\my-f-script.ps1
PS1> my-f
PS1> $my-f-var
2
Run Code Online (Sandbox Code Playgroud)

我希望这$my-f-var是无法访问的,因为在函数内部!有没有办法让变量变为私有,或者在没有点源脚本的情况下调用函数的方法?

Kei*_*ill 14

除非您点击函数名称的调用,否则函数中的变量是该范围的本地变量.当您点源脚本时,顶级脚本变量会与函数定义一起有效地导入当前作用域,例如:

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>
Run Code Online (Sandbox Code Playgroud)

请注意,$ {my-f-var}未在本地范围中定义.但是,如果我'调用'函数的调用,那么它的内容在当前范围内运行,例如:

PS> . my-f
PS> ${my-f-var}
2
Run Code Online (Sandbox Code Playgroud)

在这种情况下,函数中设置的变量在当前(调用)范围内设置,因为用于调用它的"点".

还有几点:您可以使用其中一个Get-Variable -scope或更方便(如果不太灵活)的全局,脚本,本地和私有修饰符来访问各种范围的变量.当您访问函数内部的变量时,可以在更高的范围内定义变量,您可以正常读取它.但是当你设置它时,PowerShell实际上是对变量进行"copy-on-write" - 从该函数向下创建一个新的副本(即它调用的其他函数).如果您真的想要修改更高范围的变量,可以使用$ 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
Run Code Online (Sandbox Code Playgroud)

请注意,在这种情况下,$foo函数内部的使用是一个拼写错误,但巧合的是,这个错字名称有一个变量.这不是函数的意图,虽然在这种情况下很难看到,但它无法正常工作.下面,我们可以使用说明local符来确保该函数仅在变量的局部范围内查找.它没有找到它,因为错字,但至少现在更容易发现错误.

PS> function testscope { $fooo = 'good'; "The value of `$fooo is $local:foo" }
PS> testscope
The value of $fooo is
Run Code Online (Sandbox Code Playgroud)

private当您不希望某些变量对函数调用的其他函数可见时,该范围很有用.

  • 使用`Set-StrictMode -v latest`可以帮助您避免意外引用外部范围的变量... (4认同)
  • 从PowerShell提示符执行`man about_scopes`.这将是一个很好的帮助主题. (2认同)