为什么本地定义的变量可以从另一个函数中成功访问? [英] Why is a variable defined locally successfully accessible from within another function?

查看:17
本文介绍了为什么本地定义的变量可以从另一个函数中成功访问?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

见下面的代码.将两个文件放在同一目录中,然后从 PS ISE 运行 Form1.ps1

See code below. Put both files in the same directory and run Form1.ps1 from the PS ISE

如您所见,(本地)变量 $localVar 是在事件处理程序 $button2_Click 中定义的.因此,我假设 $localVar 不会/不可能存在于 $button2_Click 范围之外,范围由定义事件处理程序的大括号定义.

As you can see, the (local) variable $localVar is defined in the event handler $button2_Click. As such, I assumed $localVar would not/could not exist outside the scope of $button2_Click with scope defined by the braces that define the event handler.

但是,如您所见,我使用 $localVar 的内容在函数 fA 中加载 $textbox2.Text.当您单击 Test 按钮时,两个文本框都会显示 $localVar

However, as you can see, I use the contents of $localVar to load $textbox2.Text in the function fA. When you click the Test button, both textboxes display the contents of $localVar

发生了什么事?为什么可以从 fA 中访问 $button2_Click$localVar?

What's going on? Why is $button2_Click's $localVar accessible from within fA?

Form1.ps1

function fA
{
    $textbox2.Text = $localVar
}

$button2_Click = 
{
    $localVar = "set in `$button2_Click"
    $textbox1.Text = $localVar
    fA
}

. (Join-Path $PSScriptRoot 'Form1.designer.ps1')

$textbox1.Text = ""
$Form1.ShowDialog()

Form1.designer.ps1

[void][System.Reflection.Assembly]::Load('System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')
[void][System.Reflection.Assembly]::Load('System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')
$Form1 = New-Object -TypeName System.Windows.Forms.Form
[System.Windows.Forms.Button]$button2 = $null
[System.Windows.Forms.TextBox]$textBox1 = $null
[System.Windows.Forms.TextBox]$textBox2 = $null
[System.Windows.Forms.Label]$label1 = $null
[System.Windows.Forms.Label]$label2 = $null
[System.Windows.Forms.Button]$button1 = $null
function InitializeComponent
{
$button2 = (New-Object -TypeName System.Windows.Forms.Button)
$textBox1 = (New-Object -TypeName System.Windows.Forms.TextBox)
$textBox2 = (New-Object -TypeName System.Windows.Forms.TextBox)
$label1 = (New-Object -TypeName System.Windows.Forms.Label)
$label2 = (New-Object -TypeName System.Windows.Forms.Label)
$Form1.SuspendLayout()
#
#button2
#
$button2.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]148,[System.Int32]12))
$button2.Name = [System.String]'button2'
$button2.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]77,[System.Int32]36))
$button2.TabIndex = [System.Int32]0
$button2.Text = [System.String]'Test'
$button2.UseVisualStyleBackColor = $true
$button2.add_Click($button2_Click)
#
#textBox1
#
$textBox1.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]67,[System.Int32]69))
$textBox1.Name = [System.String]'textBox1'
$textBox1.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]106,[System.Int32]20))
$textBox1.TabIndex = [System.Int32]1
#
#textBox2
#
$textBox2.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]247,[System.Int32]69))
$textBox2.Name = [System.String]'textBox2'
$textBox2.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]106,[System.Int32]20))
$textBox2.TabIndex = [System.Int32]2
#
#label1
#
$label1.AutoSize = $true
$label1.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]12,[System.Int32]72))
$label1.Name = [System.String]'label1'
$label1.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]47,[System.Int32]13))
$label1.TabIndex = [System.Int32]3
$label1.Text = [System.String]'textbox1'
#
#label2
#
$label2.AutoSize = $true
$label2.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]194,[System.Int32]72))
$label2.Name = [System.String]'label2'
$label2.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]47,[System.Int32]13))
$label2.TabIndex = [System.Int32]4
$label2.Text = [System.String]'textbox2'
#
#Form1
#
$Form1.ClientSize = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]374,[System.Int32]110))
$Form1.Controls.Add($label2)
$Form1.Controls.Add($label1)
$Form1.Controls.Add($textBox2)
$Form1.Controls.Add($textBox1)
$Form1.Controls.Add($button2)
$Form1.Name = [System.String]'Form1'
$Form1.ResumeLayout($false)
$Form1.PerformLayout()
Add-Member -InputObject $Form1 -Name base -Value $base -MemberType NoteProperty
Add-Member -InputObject $Form1 -Name button2 -Value $button2 -MemberType NoteProperty
Add-Member -InputObject $Form1 -Name textBox1 -Value $textBox1 -MemberType NoteProperty
Add-Member -InputObject $Form1 -Name textBox2 -Value $textBox2 -MemberType NoteProperty
Add-Member -InputObject $Form1 -Name label1 -Value $label1 -MemberType NoteProperty
Add-Member -InputObject $Form1 -Name label2 -Value $label2 -MemberType NoteProperty
Add-Member -InputObject $Form1 -Name button1 -Value $button1 -MemberType NoteProperty
}
. InitializeComponent

推荐答案

函数 fA 看到你的变量,因为它运行在脚本块的 child 范围内,其中$localVar 已创建 - 这是一般 PowerShell 行为,并非特定于 ISE.

Function fA sees your variable, because it runs in a child scope of the script block in which $localVar was created - this is general PowerShell behavior, and not specific to the ISE.

当你创建一个带有 $localVar = ... 的变量时,它是 local 在以下意义上的:

When you create a variable with $localVar = ..., it is local in the following sense:

  • 可见且可直接修改在同一范围内,但不在任何范围内.

  • visible and directly modifiable in the same scope, but not in any parent scopes.

可见所有子作用域中,但不能在那里直接修改.

visible in all child scopes, but not directly modifiable there.

  • 警告:从 模块 在一个单独的范围域(又名会话(子)状态)中运行,它只共享全局 范围作为祖先,代码在模块之外和其他模块中运行.因此,如果调用者在非模块代码中(全局范围除外)或来自不同模块,则从函数导入的模块不会看到其调用者的变量(以及函数和别名).
    另一种说法:从模块导入的函数确实在非模块调用者的子范围内(在全局范围之外)运行,因此不会看不到调用者的定义.

  • Caveat: Functions imported from modules run in a separate scope domain (a.k.a. session (sub)state) that only shares the global scope as an ancestor with code running outside of modules and in other modules. Therefore, a module imported from a function does not see its caller's variables (and functions and aliases), if the caller is in non-module code (other than the global scope) or from a different module.
    Another way of putting it: a function imported from a module does not run in a child scope of a non-module caller (outside the global scope), and therefore doesn't see that caller's definitions.

您可以使用 $private: 范围修饰符来防止子范围看到变量.

You can use the $private: scope modifier to prevent child scopes from seeing a variable.

如果您分配给最初在 parent 范围内创建的变量(仅按名称),(例如,$localVar = ...),您将改为在 当前 范围内创建一个 局部变量,它隐藏原始变量.

If you assign to a variable (by name only) that was originally created in a parent scope, (e.g., $localVar = ...), you'll instead create a new, local variable, in the current scope, which shadows the original variable.

  • 可以修改父作用域的变量,但您需要使用 Set-Variable -Scope 或作用域修饰符,例如 $script:(见下面的链接).
  • It is possible to modify a parent scope's variables, but you need to use either Set-Variable -Scope or a scope modifier such as $script: (see links below).

有关详细信息,请参阅:

For more information, see:

这个答案的最后一部分,提供了一个简洁的摘要.

the last section of this answer, which provides a concise summary.

这篇关于为什么本地定义的变量可以从另一个函数中成功访问?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆