繁体   English   中英

PowerShell 5.1 有人可以解释哈希表和 splatting

[英]PowerShell 5.1 Can someone please explain hashtable and splatting

鉴于:
PowerShell 5.1

我在理解哈希表和 splatting 时遇到了一些麻烦。 splatting 是使用 hash 表来做的,还是完全不同的东西?

我有以下代码:

$hashtable1 = @{}       
$hashtable1.add('PROD',@{ FirstName = 'John'; LastName = 'Smith'})

function Main() {
    $sel = $hashtable1['PROD']
    
    Function1 $sel    
    Function2 @sel
}

function Function1([hashtable] $x) {
    "Value: $($x.LastName)"
    $x.FirstName
}

function Function2([string] $firstName) {
    "Value: $($firstName)"
}

Main

在此处输入图像描述

Splatting和hashtables在PowerShell中是相关的概念,但它们不是一回事。

哈希表是 PowerShell 中的一种数据结构,可让您存储键值对。 你可以把它想象成其他编程语言中的字典或关联数组。 您可以使用 @{} 符号创建哈希表,然后使用 = 运算符添加键值对,如下所示:

$hashtable = @{
    "Key1" = "Value1"
    "Key2" = "Value2"
}

另一方面,Splatting 是一种允许您使用 @ 符号将参数值集合传递给命令或 function 的技术。 当您在包含哈希表的变量前使用 @ 符号时,PowerShell 会自动将哈希表扩展为其单独的键值对,并将它们作为单独的 arguments 传递给命令或 function。

例如,您可以使用 splatting 调用 function 并将哈希表中的值作为 arguments 传递:

function MyFunction([string]$Name, [int]$Age) {
    Write-Host "Name: $Name"
    Write-Host "Age: $Age"
}

$parameters = @{
    "Name" = "John"
    "Age" = 30
}

MyFunction @parameters

这将调用 MyFunction function,分别传递值“John”和 30 作为 Name 和 Age arguments。

@postanote 有一些关于哈希表和 splatting 的非常好的链接,是很好的读物。 以您的示例为例,您有两个不同的功能。 一个将哈希表作为参数处理,第二个只能处理单个字符串参数。 hashtable不能用来给第二个function传递参数,eg:

PS C:\> Function2 $sel
Value: System.Collections.Hashtable

从概念上讲,使用哈希表和 splatting 之间的真正区别不在于如何使用它们将信息和参数传递给函数,而在于函数及其参数如何接收信息

是的,某些函数可以将哈希表和 arrays 作为参数,但是,通常在 98% 的情况下,函数使用哈希表作为命名参数来获取其值。

对于前。 Copy-Item不使用 hash 表作为参数。 如果是这样,您是否希望每次复制任何内容时都这样做:

$hashtable = @{
  Path = "C:\Temp\myfile.txt",
  Destination = "C:\New Folder\"
}
Copy-Item -Parameters $hashtable

不,相反,您希望将参数作为字符串,这样您就可以使它成为一个更简单的衬里:

Copy-Item -Path "C:\Temp\myfile.txt" -Destination "C:\New Folder\"

对于大多数人来说,处理单个strings比传递一个通用的、大的、哈希表“配置”更有意义。 此外,通过将参数分离为单独的字符串、整数、浮点数、字符等,也更容易进行验证、默认值、强制/非强制参数等。

尽管说了这么多,但在某些情况下,您的某些函数有很多参数(例如发送 email 消息),或者您想多次执行某些操作(例如从 CSV 文件复制/移动大量文件)。 在这种情况下,使用哈希表和/或 arrays 和/或 arrays 哈希表会很有用。

这就是 splating 的用武之地。它需要一个哈希表,而不是像传递单个值那样对待它(即为什么Function2 $sel返回System.Collections.Hashtable ), @符号告诉 PowerShell 它是一个值的集合,并使用该集合尝试匹配 function 的参数。这就是为什么将散列表传递给Function2不起作用,但 splatting 起作用的原因,例如:

PS C:\> Function2 @sel
Value: John

在这种情况下,它采用哈希表$sel并通过使用@sel PowerShell 现在知道不按原样传递哈希表,而是打开集合并将$sel.FirstName-Firstname参数匹配。

现有答案中有很好的信息,但让我尝试进行重点总结:

您的实际问题的答案是:

  • 是的, @{ FirstName = 'John'; LastName = 'Smith' } @{ FirstName = 'John'; LastName = 'Smith' }也是一个哈希表,即以声明性哈希表文字的形式 - 就像@{}是一个的哈希表文字(它构造一个最初没有条目的实例)。

    • 哈希表字面量由零个或多个键值对组成,每个键与其值之间用=分隔,键值对之间用;分隔。 或换行符。
    • 键通常不需要引号(例如FirstName ),除非它们包含特殊字符(例如空格)或者它们是通过表达式(例如变量引用)提供的; 有关详细信息,请参阅此答案
  • 这与稍后编程方式将条目添加到哈希表形成对比,因为您的$hashtable1.Add('PROD', ...)方法调用举例说明(其中PROD是条目,而...是条目的占位符) .

    • 请注意,使用.Add()方法的一种更方便的替代方法是使用索引表达式甚至点符号(类似属性的访问),但请注意,它会根据情况添加条目或更新现有条目: $hashtable1['PROD'] =...$hashtable1.PROD =...

问题标题所暗示的更广泛问题的答案:

  • PowerShell 的哈希表是一种数据结构,通常称为字典,或者在其他语言中称为关联数组map 具体来说,它们是 .NET [hashtable] ( System.Collections.Hashtable ) 类型的不区分大小写的实例,它是无序键值对条目的集合。 哈希表可以通过关联的键高效地查找值。

    • 通过语法糖[ordered] @{... } ,即通过将[ordered]放在哈希表文字之前,PowerShell 提供了一个不区分大小写的有序字典,它维护条目定义顺序并允许除了通常的位置索引之外的访问基于密钥的访问。 此类有序哈希表是 .NET System.Collections.Specialized.OrderedDictionary类型的不区分大小写的实例。

      • 一个简单的例子:

         # Create an ordered hashtable (omit [ordered] for an unordered one). $dict = [ordered] @{ foo = 1; bar = 'two' } # All of the following return 'two' $dict['bar'] # key-based access $dict.bar # ditto, with dot notation (property-like access) $dict[1] # index-based access; the 2nd entry's value.
  • Splatting是一种参数传递技术,它可以通过包含编码 arguments 的数据结构的变量间接传递 arguments ,这对于动态构造 arguments 并使调用许多 arguments 更具可读性很有用。

    • 通常且稳健 - 但仅当调用带有声明参数PowerShell命令时- 该数据结构是一个hashtable ,其条目键必须与目标命令的参数名称(例如,键Path目标参数-Path )匹配,并且其条目值指定通过。

      • 换句话说:这种形式的 splatting 使用哈希表来实现名为arguments 的传递(参数值前面是目标参数的名称,例如直接参数传递中的-Path /foo )。

      • 一个简单的例子:

         # Define the hashtable of arguments (parameter name-value pairs) # Note that File = $true is equivalent to the -File switch. $argsHash = @{ LiteralPath = 'C:\Windows'; File = $true } # Note the use of "@" instead of "$"; equivalent to: # Get-ChildItem -LiteralPath 'C:\Windows' -File Get-ChildItem @argsHash
    • 或者,数组可用于展开,仅包含参数,然后按位置将其传递给目标命令。

      • 换句话说:这种形式的splatting使用数组来实现传递位置arguments仅参数值)。

      • 这种形式通常只在以下情况下有用:

        • 调用 PowerShell 脚本或函数时,这些脚本或函数未正式声明参数并通过自动$args变量访问它们的 - 总是位置- arguments
        • 调用外部程序时; 请注意,从PowerShell的角度来看,在调用外部程序时没有named arguments的概念,因为PowerShell对这种情况下的参数语法一无所知,所有arguments只是简单地一一放在进程命令行中,它取决于目标程序将它们解释为参数名称与值。
      • 一个简单的例子:

         # Define an array of arguments (parameter values) $argsArray = 'foo', 'bar' # Note the use of "@" instead of "$", though due to calling an # *external program* here, you may use "$" as well; equivalent to: # cmd /c echo 'foo' 'bar' cmd /c echo @argsArray

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM