gpt4 book ai didi

collections - 是什么决定了Powershell管道是否将展开一个集合?

转载 作者:行者123 更新时间:2023-12-04 03:41:33 27 4
gpt4 key购买 nike

# array
C:\> (1,2,3).count
3
C:\> (1,2,3 | measure).count
3

# hashtable
C:\> @{1=1; 2=2; 3=3}.count
3
C:\> (@{1=1; 2=2; 3=3} | measure).count
1

# array returned from function
C:\> function UnrollMe { $args }
C:\> (UnrollMe a,b,c).count
3
C:\> (UnrollMe a,b,c | measure).count
1
C:\> (1,2,3).gettype() -eq (UnrollMe a,b,c).gettype()
True

与HashTables的差异为 fairly well known,尽管 official documentation只是倾斜地提及(例如)。

但是,功能问题对我来说是个新闻。我有点震惊,直到现在还没有咬我。我们的脚本编写者可以遵循一些指导原则吗?我知道用C#编写cmdlet时,存在一个 overload of WriteObject,您可以在其中显式控制枚举,但是AFAIK在Posh语言本身中没有这样的构造。如最后一个示例所示,Posh解释器似乎认为管道对象的类型没有区别。我怀疑引擎盖下可能存在一些Object vs PSObject怪异之处,但是当您编写纯Posh并期望脚本语言“可以正常工作”时,这没什么用。

/编辑/

Keith正确指出,在我的示例中,我传递的是单个string []参数,而不是3个字符串参数。换句话说,Measure-Object之所以说Count = 1的原因是因为它看到单个数组,数组的第一个元素是@(“a”,“b”,“c”)。很公平。这些知识使您可以通过多种方式解决此问题:
# stick to single objects
C:\> (UnrollMe a b c | measure).count
3

# rewrite the function to handle nesting
C:\> function UnrollMe2 { $args[0] }
C:\> (UnrollMe2 a,b,c | measure).count
3

# ditto
C:\> function UnrollMe3 { $args | %{ $_ } }
C:\> (UnrollMe3 a,b,c | measure).count
3

然而,它并不能解释一切。
# as seen earlier - if we're truly returning @( @("a","b","c") ) why not count=1?
C:\> (UnrollMe a,b,c).count
3

# our theory must also explain these results:
C:\> ((UnrollMe a,b,c) | measure).count
3
C:\> ( @(@("a","b","c")) | measure).count
3
C:\> ((UnrollMe a,b,c d) | measure).count
2

根据我的推断,还有另外一条规则在起作用:如果您的数组中只有一个元素并且解析器在 expression mode中,则解释器将“解包”所述元素。还有更多我想念的微妙之处吗?

最佳答案

$ args已展开。请记住,函数参数通常使用空格传递以分隔它们。当您传入1,2,3时,您传入的是一个参数,该参数是由三个数字组成的数组,并分配给$ args [0]:

PS> function UnrollMe { $args }
PS> UnrollMe 1 2 3 | measure

Count : 3

将结果(数组)放入分组表达式(或子表达式,例如 $())中,使其再次符合展开条件,因此以下内容将展开包含UnrollMe返回的1,2,3的object []:
PS> ((UnrollMe 1,2,3) | measure).Count
3

等效于:
PS> ((1,2,3) | measure).Count
3

顺便说一句,它不仅适用于具有一个元素的数组。
PS> ((1,2),3) | %{$_.GetType().Name}
Object[]
Int32

在已经是数组的对象上使用数组子表达式( @())无效,无论您应用了多少次。 :-)如果要防止展开,请使用逗号运算符,因为它将始终创建另一个展开的外部数组。请注意,在这种情况下,您并没有真正阻止展开,而只是通过引入一个外部的“包装器”数组来展开,而不是原始数组,从而解决了展开问题,例如:
PS> (,(1,2,3) | measure).Count
1

最后,当您执行此操作时:
PS> (UnrollMe a,b,c d) | %{$_.GetType().Name}
Object[]
String

您可以看到UnrollMe返回两个项(a,b,c)作为数组,而d作为标量。这两个项目分别沿管道发送,结果计数为2。

关于collections - 是什么决定了Powershell管道是否将展开一个集合?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1827862/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com