了解PowerShell 5.1中的哈希表和splatting

djp7away  于 2023-03-23  发布在  Shell
关注(0)|答案(2)|浏览(215)

我用的是PowerShell 5.1。
我在理解哈希表和splatting时遇到了麻烦。splatting是使用哈希表来实现的,还是完全不同的东西?
下面的代码:

$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

5fjcxozz

5fjcxozz1#

在现有的答案中有很好的信息,但让我尝试一个集中的总结:

您的实际问题的答案是:

  • 是的,@{ FirstName = 'John'; LastName = 'Smith' }也是一个hashtable,即声明性的hashtable literal的形式-就像@{}是一个 empty hashtable literal(它构造了一个最初没有条目的示例)。
  • 哈希表文字由零个或多个键-值对组成,=将每个键与其值分隔开,并使用;或换行符分隔。
  • 键通常不需要 * 引号 *(例如FirstName),除非它们包含特殊字符,例如空格,或者通过 * 表达式 * 提供,例如变量引用;详情请参见this answer
  • 这与稍后 * 以 * 编程方式*向哈希表添加条目形成对比,如$hashtable1.Add('PROD', ...)方法调用所示(其中PROD是条目 key...是条目 value 的占位符)。
  • 请注意,使用.Add()方法的一个更方便的替代方法是使用 index expression 或甚至 dot notation(类似于属性的访问),但请注意,它可能会根据情况 * 添加 * 一个条目或 * 更新一个现有条目 *:$hashtable1['PROD'] = ...$hashtable1.PROD = ...

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

PowerShell的hashtables是一种数据结构,通常称为dictionary or, in other languages, associative array or 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是一种参数传递技术,它**通过包含参数编码数据结构的 * 变量*间接传递参数,这对于动态构造参数和使具有许多参数的调用更具可读性非常有用。

    • 通常情况下 ,而且是可靠的--但仅在调用 PowerShell 命令时带有 * 声明的参数***--该数据结构是***哈希表***,其条目键必须与目标命令的参数的 * 名称 * 匹配(例如,键Path目标参数-Path),并且其条目值指定要传递的 * 值 *。
  • 换句话说:这种形式的splatting使用哈希表来实现passing named arguments(参数值前面是目标参数的名称,例如 direct arguments passing中的-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,仅包括参数 * 值 *,然后将参数 * 值 * 按位置 * 传递给目标命令。
  • 换句话说:这种形式的splatting使用数组来实现传递 * 位置 * 参数(仅参数 * 值 *)。
  • 此表单通常仅适用于:
  • 调用未正式声明参数的PowerShell脚本或函数并通过自动$args变量访问其始终 * 位置 * 参数时
    调用 * 外部程序时;注意,从PowerShell的Angular 来看,在调用外部程序时没有 named 参数的概念,因为PowerShell对这种情况下的参数语法一无所知,所有参数都只是一个接一个地放在进程命令行上,并且由目标程序将它们解释为参数名称与值。
  • 举个简单的例子:
# 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
fnx2tebb

fnx2tebb2#

@postanote有一些关于哈希表和splatting的非常好的链接,是很好的读物。以你的例子为例,你有两个不同的函数。一个处理哈希表作为参数,第二个只能处理单个字符串参数。哈希表不能用来向第二个函数传递参数,例如:

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

从概念上讲,使用哈希表和splatting之间的真实的区别不是如何使用它们向函数传递信息和参数,而是函数 * 和它们的 * 参数如何接收 * 信息**。
是的,某些函数可以使用哈希表和数组作为参数,但是,通常在98%的情况下,函数使用哈希表作为命名参数来获取其值。
例如,Copy-Item不使用哈希表作为参数。如果它使用哈希表,您是否希望在每次复制任何内容时都这样做:

$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比传递一个通用的、大的、散列表的“配置”更有意义。此外,通过将参数分离为单独的字符串、整数、浮点数、字符等,也更容易进行验证、默认值、强制/非强制参数等。
现在,尽管说了这么多,但有一种情况是,你有一些带有很多参数的函数(例如发送电子邮件),或者你想多次做一些事情(例如从CSV文件中复制/移动很多文件)。在这种情况下,使用哈希表和/或数组和/或哈希表数组将是有用的。
这就是splating的用武之地。它接受一个哈希表,而不是像传递单个值那样对待它(例如,为什么Function2 $sel返回System.Collections.Hashtable),@符号告诉PowerShell它是一个值的集合,并使用该集合尝试匹配函数的参数。这就是为什么将哈希表传递给Function2不起作用,但溅射起作用,例如:

PS C:\> Function2 @sel
Value: John

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

相关问题