PowerShell的一个令人遗憾的事情是函数和脚本块是动态范围的.
但另一件让我感到惊讶的事情是变量在内部范围内表现为写时复制.
$array=@("g")
function foo()
{
$array += "h"
Write-Host $array
}
& {
$array +="s"
Write-Host $array
}
foo
Write-Host $array
Run Code Online (Sandbox Code Playgroud)
输出是:
g s
g h
g
Run Code Online (Sandbox Code Playgroud)
这使动态范围变得不那么痛苦.但是我如何避免写时复制?
Ant*_*rin 86
PowerShell范围文章(about_Scopes)很好,但是太冗长了,所以这是我文章的引用:
通常,PowerShell作用域类似于.NET作用域.他们是:
这是一个简单的例子,它描述了范围的用法和效果:
$test = 'Global Scope'
Function Foo {
$test = 'Function Scope'
Write-Host $Global:test # Global Scope
Write-Host $Local:test # Function Scope
Write-Host $test # Function Scope
Write-Host (Get-Variable -Name test -ValueOnly -Scope 0) # Function Scope
Write-Host (Get-Variable -Name test -ValueOnly -Scope 1) # Global Scope
}
Foo
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,您可以使用$ Global:test like语法仅与命名范围一起使用,$ 0:test将始终为$ null.
Ric*_*ard 72
您可以使用范围修饰符或*-Variablecmdlet.
范围修饰符是:
global 用于访问/修改最外层的范围(例如,交互式shell)script用于访问/修改运行脚本(.ps1文件)的范围.如果没有运行脚本则运行为global.(有关cmdlet 的-Scope参数,*-Variable请参阅帮助.)
例如.在你的第二个例子中,直接修改全局$array:
& {
$global:array +="s"
Write-Host $array
}
Run Code Online (Sandbox Code Playgroud)
有关更多详细信息,请参阅帮助主题about_scopes.
mjo*_*nor 17
不只是变数.当这表示"item"时,它表示变量,函数,别名和psdrives.所有这些都有范围.
LONG DESCRIPTION
Windows PowerShell protects access to variables, aliases, functions, and
Windows PowerShell drives (PSDrives) by limiting where they can be read and
changed. By enforcing a few simple rules for scope, Windows PowerShell
helps to ensure that you do not inadvertently change an item that should
not be changed.
The following are the basic rules of scope:
- An item you include in a scope is visible in the scope in which it
was created and in any child scope, unless you explicitly make it
private. You can place variables, aliases, functions, or Windows
PowerShell drives in one or more scopes.
- An item that you created within a scope can be changed only in the
scope in which it was created, unless you explicitly specify a
different scope.
您看到的写入问题的副本是因为Powershell处理数组的方式.添加到该数组实际上会破坏原始数组并创建一个新数组.由于它是在该范围内创建的,因此在函数或脚本块退出并且范围被处理时会被销毁.
您可以在更新varible时更新它们,或者可以使用[ref]对象进行更新,或者编写脚本以便更新对象的属性或对象或哈希表的哈希表键.父范围.这不会在本地作用域中创建新对象,它会修改父作用域中的对象.
虽然其他帖子提供了很多有用的信息,但它们似乎只是为了让您免受 RTFM 的困扰。
未提及的答案是我认为最有用的答案!
([ref]$var).value = 'x'
Run Code Online (Sandbox Code Playgroud)
这会修改$var的值, 无论它恰好在什么范围内。您不需要知道它的范围;只是它实际上已经存在了。使用OP的例子:
$array=@("g")
function foo()
{
([ref]$array).Value += "h"
Write-Host $array
}
& {
([ref]$array).Value +="s"
Write-Host $array
}
foo
Write-Host $array
Run Code Online (Sandbox Code Playgroud)
生产:
g s
g s h
g s h
Run Code Online (Sandbox Code Playgroud)
说明:
([ref]$var)获取指向变量的指针。由于这是一个读取操作,因此它解析为实际创建该名称的最新范围。它还解释了如果变量不存在的错误,因为 [ref] 无法创建任何内容,它只能返回对已存在的内容的引用。
.value然后将您带到保存变量定义的属性;然后您可以设置。
您可能会想做这样的事情,因为有时看起来确实有效。
([ref]$var) = "New Value"
Run Code Online (Sandbox Code Playgroud)
不!!!!
它看起来有效的情况是一种错觉,因为 PowerShell 正在做一些它只在某些非常狭窄的情况下(例如在命令行上)做的事情。你不能指望它。事实上,它在 OP 示例中不起作用。
| 归档时间: |
|
| 查看次数: |
117361 次 |
| 最近记录: |