变量范围:VBA 如何决定何时覆盖变量 [英] Variable Scope: How VBA Decides When to Override Variables

查看:50
本文介绍了变量范围:VBA 如何决定何时覆盖变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下 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 即使它强制要在其函数定义中更改的变量?

解决方案

关于作用域,FunctionSub 的参数只在 Function 内有作用域Sub 声明它们.对于使用关键字 Dim(或用于数组的 ReDim).对于未声明变量,如果存在匹配的标识符(模块级私有变量,然后是全局变量),则作用域是下一个最高作用域.如果不存在具有更大范围的标识符,则在 local 范围内将其隐式声明为 Variant.所以,在这一行...

<块引用>

Sub convert(speedmph, speedkph, speedfts)

...参数speedmphspeedkphspeedfts 都是Sub convert 的本地参数(和是隐式的 Variant 因为没有 As 语句),并且在这一行...

<块引用>

将speedmph设为双倍,将speedkph设为双倍,将speedfts设为双倍

...参数speedmphspeedkphspeedfts 都是Sub problem1() 的本地参数.

<小时>

顺便说一下,让我们解决为什么您的 MsgBox 显示任何内容.传递参数的默认方法是 ByRef,因此,如果您要实际指定 Sub 声明的所有隐式部分,它将如下所示:

Public Sub convert(ByRef speedmph As Variant, ByRef speedkph As Variant, _ByRef speedfts 作为变体)

当你这样称呼它时......

<块引用>

调用转换(speedmph, speedkph, speedfts)

...你将它引用传递给局部变量speedmphspeedkphspeedfts 您在 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屋!

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