变量范围:VBA 如何决定何时覆盖变量 [英] Variable Scope: How VBA Decides When to Override Variables
问题描述
我有以下 VBA 代码.
选项显式子问题1()Dim speedmph As Double, speedkph As Double, speedfts As Doublespeedmph = Val(InputBox("输入速度(mph)"))调用转换(speedmph、speedkph、speedfts)MsgBox "速度是" &速度和速度公里/小时和" &速度&英尺/秒."结束子子转换(speedmph,speedkph,speedfts)speedkph = 速度mph * 1.609speedfts = 速度英里 * 1.467结束子
我注意到当我调用上面显示的转换过程时,它起作用了.但是,如果我尝试为 speedkph 插入一个值(例如 0),convert
过程不会覆盖它,MsgBox 会为 speedkph 打印 0.
为什么 convert
不覆盖 0
即使它强制要在其函数定义中更改的变量?
关于作用域,Function
或 Sub
的参数只在 Function 内有作用域
或 Sub
声明它们.对于使用关键字 Dim
(或用于数组的 ReDim
).对于未声明变量,如果存在匹配的标识符(模块级私有变量,然后是全局变量),则作用域是下一个最高作用域.如果不存在具有更大范围的标识符,则在 local 范围内将其隐式声明为 Variant
.所以,在这一行...
Sub convert(speedmph, speedkph, speedfts)
...参数speedmph
、speedkph
和speedfts
都是Sub convert
的本地参数(和是隐式的 Variant
因为没有 As
语句),并且在这一行...
将speedmph设为双倍,将speedkph设为双倍,将speedfts设为双倍
...参数speedmph
、speedkph
和speedfts
都是Sub problem1()
的本地参数.
顺便说一下,让我们解决为什么您的 MsgBox
显示任何内容.传递参数的默认方法是 ByRef
,因此,如果您要实际指定 Sub
声明的所有隐式部分,它将如下所示:
Public Sub convert(ByRef speedmph As Variant, ByRef speedkph As Variant, _ByRef speedfts 作为变体)
当你这样称呼它时......
<块引用>调用转换(speedmph, speedkph, speedfts)
...你将它引用传递给局部变量speedmph
、speedkph
、speedfts
您在 Sub problem1()
中声明.Sub convert
为这些引用赋值,但每个过程只在局部范围内保存它自己的副本引用.标识符在这一点上是完全不相关的.实际上,这与您的示例代码完全相同(仅更改了标识符):
子问题1()Dim speedmph As Double, speedkph As Double, speedfts As Doublespeedmph = Val(InputBox("输入速度(mph)"))调用转换(speedmph,speedkph,speedfts)MsgBox "速度是" &速度和速度公里/小时和" &速度&英尺/秒."结束子子转换(foo,bar,baz)bar = foo * 1.609baz = foo * 1.467结束子
<小时>
现在回答您的具体问题,您不能使用 0
的占位符"值的原因是 0
不是变量 - 它是文字.当它传递给 Sub convert
时,引用存在的唯一位置是调用堆栈上的变量 - Sub problem1()
不保存对它的引用,所以Sub problem1()
没有办法告诉 Sub convert
用它做什么.当 Sub convert
返回并且调用堆栈展开时,堆栈变量被销毁.基本上,将文字传递给 ByRef
参数在功能上等同于将其传递给 ByVal
.
I have the following VBA code.
Option Explicit
Sub problem1()
Dim speedmph As Double, speedkph As Double, speedfts As Double
speedmph = Val(InputBox("Enter a speed (mph)"))
Call convert(speedmph, speedkph, speedfts)
MsgBox "The speed is " & speedkph & " km/hr and " & speedfts & "ft/s."
End Sub
Sub convert(speedmph, speedkph, speedfts)
speedkph = speedmph * 1.609
speedfts = speedmph * 1.467
End Sub
I've noticed that when I called the convert procedure as it is shown above, it worked.
But if I tried to insert a value for speedkph (e.g. 0), the convert
procedure does not override that and MsgBox prints out 0 for speedkph.
Why doesn't convert
override the 0
even though it forces
the variable to change in its function definition?
Regarding scope, the parameters for a Function
or Sub
only have scope within the Function
or Sub
that they are declared in. The same thing holds true for variables declared with the keyword Dim
(or ReDim
for arrays). For undeclared variables, the scope is the next highest scope if a matching identifier exists (module level private variables, then global variables). If no identifier with a greater scope exists, it is implicitly declared as a Variant
in local scope. So, in this line...
Sub convert(speedmph, speedkph, speedfts)
...the parameters speedmph
, speedkph
, and speedfts
are all local to Sub convert
(and are implicitly Variant
because there aren't As
statements), and in this line...
Dim speedmph As Double, speedkph As Double, speedfts As Double
...the parameters speedmph
, speedkph
, and speedfts
are all local to Sub problem1()
.
That out of the way, let's address why your MsgBox
shows anything at all. The default method of passing parameters is ByRef
, so if you were to actually specify all of the implicit parts of your Sub
declaration, it would look like this:
Public Sub convert(ByRef speedmph As Variant, ByRef speedkph As Variant, _
ByRef speedfts As Variant)
When you call it like this...
Call convert(speedmph, speedkph, speedfts)
...you pass it references to the local variables speedmph
, speedkph
, speedfts
you declared in Sub problem1()
. The Sub convert
assigns values to those references, but each procedure only holds it's own copy of the reference in local scope. The identifiers are completely irrelevant at this point. In fact, this works exactly the same as your sample code (only the identifiers have been changed):
Sub problem1()
Dim speedmph As Double, speedkph As Double, speedfts As Double
speedmph = Val(InputBox("Enter a speed (mph)"))
Call convert(speedmph, speedkph, speedfts)
MsgBox "The speed is " & speedkph & " km/hr and " & speedfts & "ft/s."
End Sub
Sub convert(foo, bar, baz)
bar = foo * 1.609
baz = foo * 1.467
End Sub
Now to answer your specific question, the reason you can't use a "placeholder" value of 0
is that 0
isn't a variable - it's a literal. When it's passed to Sub convert
, the only place the reference exists is as a variable on the call stack - Sub problem1()
doesn't hold a reference to it, so there's no way for Sub problem1()
to tell what Sub convert
does with it. The stack variable is destroyed when Sub convert
returns and the call stack unwinds. Basically, passing a literal to a ByRef
parameter is functionally equivalent to passing it ByVal
.
这篇关于变量范围:VBA 如何决定何时覆盖变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!