【问题标题】:Type mismatch when passing string variable into Variant parameter, and assigning result of Array function to parameter将字符串变量传递给 Variant 参数时类型不匹配,并将 Array 函数的结果分配给参数
【发布时间】:2018-07-10 19:04:36
【问题描述】:

我有以下两个程序:

Sub OuterSub()
    Dim s As String
    s = "Lorem ipsum dolor sit amet"
    InnerSub s
End Sub

Sub InnerSub(prm As Variant)
    prm = Array(prm)
End Sub

当我运行 OuterSub 时,我在 prm = Array(prm) in InnerSub 中收到以下错误:

运行时错误“13”:类型不匹配

只有当我传入一个类型为 String 的变量时才会发生这种情况。以下任何替代方案都不会产生错误:

  • OuterSub 中的s 定义为常量:
    Const s = "Lorem ipsum dolor sit amet"
  • 传入字符串文字:
    InnerSub "Lorem ipsum dolor sit amet"
  • OuterSub 中的s 定义为Variant:
    Dim s As Variant

s 定义为固定长度的字符串没有帮助。

为什么会这样?我该如何解决?


更新

InnerSub 中声明一个本地String 变量也无济于事:

Sub InnerSub(prm As Variant)
    Dim s As String
    s = prm
    prm = Array(s)
End Sub

也不将参数括在括号中:

Sub InnerSub(prm As Variant)
    prm = Array((prm))
End Sub

【问题讨论】:

    标签: vba


    【解决方案1】:

    这里的参数定义:

    Sub InnerSub(prm As Variant)
    

    隐含为ByRef:

    Sub InnerSub(ByRef prm As Variant)
    

    这意味着对prm 的任何分配也将分配给OuterSub 中的s。虽然可以将数组分配给Variant 变量prm,但它不能分配给OuterSub 中的String 变量s

    您可以通过在OuterSub 中定义s As Variant(持有数组没有问题)并在InnerSub 完成后检查s 的值来看到这一点。

    您可以显式强制在ByVal 中传递一个变量:

    Sub InnerSub(ByVal prm As Variant)
    

    传递一个常量:

    Const s = "Lorem ipsum dolor sit amet"
    

    或字符串文字:

    InnerSub "Lorem ipsum dolor sit amet"
    

    两者都有效,因为两者都不能传入ByRef

    将参数括在方括号中也会强制将变量传递到ByVal,这就是为什么以下工作的原因

    Sub OuterSub()
        Dim s As String
        s = "Lorem ipsum dolor sit amet"
        InnerSub (s) ' The brackets here do the trick
    End Sub
    

    OTOH,您的非工作替代方案都不起作用,因为无论您创建本地字符串变量,还是将参数包装到括号中的 Array,问题都是一样的——您正在尝试分配一个数组通过ByRef prm 参数传递给字符串变量。


    查看我对CallByName won't accept variant arguments 的回复。引用该答案中引用的链接:

    如何:强制按值传递参数 (Visual Basic)

    过程声明决定了传递机制。如果参数声明为 ByRef,Visual Basic 期望通过引用传递相应的参数。这允许过程更改调用代码中参数基础的编程元素的值。如果您希望保护底层元素免受此类更改,您可以通过将参数名称括在括号中来覆盖过程调用中的 ByRef 传递机制。这些括号是对调用中参数列表的括号的补充。

    调用代码不能覆盖 ByVal 机制。

    强制参数按值传递 如果相应的参数在过程中声明为 ByVal,则不需要采取任何额外的步骤。 Visual Basic 已经希望按值传递参数。

    如果相应的参数在过程中声明为ByRef,则在过程调用中将参数括在括号中。

    【讨论】:

    • 请注意,Sub InnerSub 也有一个隐式的Public 访问修饰符;这是 75+ things Rubberduck can warn you about 之一,隐含的(或多余的,取决于您如何看待)ByRef 修饰符也是如此。
    【解决方案2】:

    我不知道原因,但似乎在传递 byref 时会抛出期望。字符串是通过引用传递的,但是如果你在它周围加上括号,它是通过值传递的:

    Sub OuterSub()
        Dim s As String
        s = "Lorem ipsum dolor sit amet"
        InnerSub (s)
    End Sub
    

    另一个选项,如果你不想改变外部函数,是通过值定义 InnerSub prm

    Sub InnerSub(ByVal prm As Variant)
        prm = Array(prm)
    End Sub
    

    【讨论】:

    • 我更愿意在 InnerSub 内部处理这个问题。
    • 我不确定,但我怀疑它可以工作,因为我认为当你用括号括起一个参数来调用时,它会将变量转换为定义的类型称为子例程,在这种情况下强制字符串返回一个变体。
    猜你喜欢
    • 2022-01-21
    • 2019-07-28
    • 1970-01-01
    • 2021-09-20
    • 2018-06-28
    • 1970-01-01
    • 2021-10-21
    • 2021-10-13
    相关资源
    最近更新 更多