【问题标题】:Is it ok to string variables together to clear them?可以将变量串在一起以清除它们吗?
【发布时间】:2020-02-22 10:58:58
【问题描述】:

因此,可以使用Clear-Variable cmdlet 清除变量,这与赋予其值$null 相同。

也可以使用Remove-Variable cmdlet 或Remove-Item cmdlet 删除环境变量的变量。

我的问题是,像这样将变量串在一起...

$Env:var1 = $var2 = $var3 = $null

...清除变量甚至赋值的合法方式?

我知道$var1 独立于$var2,如果您分配这样的值:$var1 = $var2 = 1,但是当该值是使用New-Object cmdlet 创建的对象时,两个变量都指向同一个对象:

$var1 = $var2 = New-Object System.Diagnostics.Stopwatch
$var1.Start()
Start-Sleep 1
$var2.Stop()
Start-Sleep 1
$var1.Elapsed.TotalMilliseconds

这仅仅是Microsoft .NET FrameworkCOM object 的值吗?

【问题讨论】:

  • $var2 = $var1 = New-Object System.Diagnostics.Stopwatch;;$var1 -eq $var2 返回true$var2 = New-Object System.Diagnostics.Stopwatch; $var1 = New-Object System.Diagnostics.Stopwatch;$var1 -eq $var2 返回false。不要问我为什么……
  • @JosefZ 根据我从您链接的文章中了解到的(谢谢!),使用 New-Object cmdlet 创建一个引用类型变量。
  • 我不这么认为;试试例如:$a = $b = New-Object string -ArgumentList "abc";$b='ccc'; $a,$b
  • @JosefZ:很好的指点,而且New-Object 也同样能够创建值类型。不过,您的具体示例需要解释:作为 异常[string](.NET 字符串)行为类似于值类型,但在技术上参考类型。

标签: powershell variable-assignment


【解决方案1】:

...清除变量的合法方式

是的,类似 $var1 = $var2 = $null(仅以 2 个变量为例)是清除变量值的合法方式,前提是目标变量实际上是在本地(当前)范围内定义的。

如果它们仅在 (祖先)范围内可见),您将无意中创建 local 同名变量,其值为 $null - 请参阅this answer.

这同样适用于 Clear-Variable var1, var2 原则上,除了如果没有 local 变量 @987654330 它会发出 error @ 和 $var2 已定义;此外,Clear-Variable 允许使用 -Scope 显式定位不同的范围。

由于限制,您还可以使用诸如$script:var 之类的范围说明符来定位具有变量分配的其他范围 - 请参阅this related answer

Remove-Variable 的作用类似于Clear-Variable,也支持-Scope,但真正从隐含或目标范围中删除(取消定义)变量。

请注意,访问已删除/不存在的变量默认情况下与访问值为$null 的现有变量实际上是相同的。 但是,在 Set-StrictMode -Version 1 或更高版本的情况下,访问不存在的变量会因设计而失败。

$var1 = $var2 = $nullClear-Variable var1, var2有以下优势

  • 它更简洁,速度也更快(无需调用 cmdlet)。
  • 它可用于隐式创建具有$null 值的变量,或者换句话说,如果其中一个变量不存在,则语句不会失败。李>
  • 它也可以与环境变量一起使用(例如,$env:FOO),但请注意实际上将$null(或'',空字符串)分配给环境变量删除 它们($env:FOO = $null 等同于 Remove-Item Env:FOO)。

警告

分配$null或调用Clear-Variable不一定会导致变量包含$null

变量可能是类型受限的在这种情况下,它们只允许存储在创建(初始化)时锁定的类型的值:

[int] $i = 1  # Create a type-constrained variable that can only store [int] values.

当您将 $null 分配给类型受限的变量时,PowerShell 会尝试将$null转换为锁定类型,这可能会产生两种结果:

  • 转换成功,此时锁定类型的转换后值为新值;例如,在[int] 的情况下,该值为0,因为[int] $null0

    [int] $i = 1; $i = $null; $i # -> 0, not $null
    
  • 转换可能失败,导致错误;在[datetime] 的情况下,转换失败,因为[datetime] $null 失败。

    # !! ERROR: Cannot convert null to type "System.DateTime"
    [datetime] $dt = Get-Date; $dt = $null 
    

至于New-Object 并为多个变量分配一个非空值:

如 cmets 中所述,结果行为归结为分配的是 value-type 实例还是 reference-type 实例[1]

  • 对于 value-type 实例,每个变量都有自己的独立副本值。

    # A value-type instance such as an [int] instance assigns
    # *independent copies* of itself to the target variable(s):
    $var1 = $var2 = 42; $var2 = 43; $var1, $var2 # -> 42, 43
    
  • 使用 reference-type 实例,所有变量都真正引用 同一个对象

    # A reference-type instance such as a [hashtable] instance assigns
    # a *reference to itself* to the target variable(s), which therefore
    # all reference the same object.
    $var1 = $var2 = @{one=1}; $var2.one = 2; $var1.one, $var2.one # -> 2, 2
    

请注意,[string] 实例是一个例外[string] 在技术上是 reference 类型,但具有 value 类型的语义,以便提供更直观的字符串处理 - 请参阅this answer

New-Object 能够实例化任何一种类型:如果你给它一个值类型的名称,你会得到一个值类型实例;给定引用类型的名称,您将获得一个引用类型实例。

但是,鉴于内置值类型可以用文字(例如,1)或简单类型转换([int])来实例化,New-Object 更常用于实例化引用类型。


[1] 给定一个类型或实例,您可以检查该类型的.IsValueType 属性以确定它是否为值类型;例如,因为[int] (System.Int32) 是值类型[int].IsValueType(1).GetType().IsValueType 产生$true,而[System.IO.FileInfo].IsValueType$false,因为后者是引用类型。 p>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-03
    • 2019-05-27
    • 1970-01-01
    • 2012-09-06
    • 1970-01-01
    • 2022-01-03
    相关资源
    最近更新 更多