【问题标题】:VBA Difference between Set and Assignment集合和赋值之间的VBA区别
【发布时间】:2018-10-23 11:25:39
【问题描述】:

我正在阅读VBA-JSON的源代码,位于:

https://github.com/VBA-tools/VBA-JSON/blob/master/JsonConverter.bas

在将 JSON 对象(以“{”字符开头)转储到内存中的函数中:

Private Function json_ParseObject(json_String As String, ByRef json_Index As Long) As Dictionary
Dim json_Key As String
Dim json_NextChar As String

Set json_ParseObject = New Dictionary
json_SkipSpaces json_String, json_Index
If VBA.Mid$(json_String, json_Index, 1) <> "{" Then
    Err.Raise 10001, "JSONConverter", json_ParseErrorMessage(json_String, json_Index, "Expecting '{'")
Else
    json_Index = json_Index + 1

    Do
        json_SkipSpaces json_String, json_Index
        If VBA.Mid$(json_String, json_Index, 1) = "}" Then
            json_Index = json_Index + 1
            Exit Function
        ElseIf VBA.Mid$(json_String, json_Index, 1) = "," Then
            json_Index = json_Index + 1
            json_SkipSpaces json_String, json_Index
        End If

        json_Key = json_ParseKey(json_String, json_Index)
        json_NextChar = json_Peek(json_String, json_Index)
        If json_NextChar = "[" Or json_NextChar = "{" Then
            Set json_ParseObject.Item(json_Key) = json_ParseValue(json_String, json_Index)
        Else
            json_ParseObject.Item(json_Key) = json_ParseValue(json_String, json_Index)
        End If
    Loop
End If
End Function

有什么区别:

Set json_ParseObject.Item(json_Key) = json_ParseValue(json_String, json_Index)

还有以下的:

json_ParseObject.Item(json_Key) = json_ParseValue(json_String, json_Index)

我在SO里搜了一下,发现了这个帖子,并没有打消疑惑:

What does the keyword Set actually do in VBA?

通过阅读代码,我了解到如果解析器读取“{”或“[”,那么它需要使用 Dictionary 来保存“{”和“}”之间的任何内容,并使用 Collection 来保存“{”和“}”之间的任何内容“[”和“]”,如果解析器读取的不是这两个,那么它只是一个值,可以是布尔值或字符串或整数等。

我不明白 Set 和 Assignment 之间的区别。 "Set" 将复制 json_ParseValue 的返回变量的地址,而赋值只是复制返回变量的另一个副本。是不是因为在第一种情况下,还需要修改返回的对象,所以它必须通过地址传递(就像在 C++ 中我们使用 &)?

【问题讨论】:

    标签: vba parsing


    【解决方案1】:

    正如链接的问答所说,Set 在 VBA 中用于分配对象引用。 Let 关键字可用于赋值,但 Let 关键字几乎已过时/冗余。

    这就是为什么您在属性修改器定义中使用这些关键字的原因:

    Private mSomething As Variant
    
    Public Property Let Something(ByVal value As Variant)
        mSomething = value ' value is a primitive
    End Property
    
    Public Property Set Something(ByVal value As Variant)
        Set mSomething = value ' value is an object reference
    End Property
    

    到目前为止,一切都很好。这之间的区别:

    Set json_ParseObject.Item(json_Key) = json_ParseValue(json_String, json_Index)
    

    还有这个:

    json_ParseObject.Item(json_Key) = json_ParseValue(json_String, json_Index)
    

    是不是因为json_ParseValue返回了一个Variant,它可以保存任何东西,包括对象引用或简单值,那么它在分配引用时需要使用Set关键字,并将其省略(或使用Let关键字)赋值时。


    如果不查看实现细节并查看返回的确切内容,就无法判断,但Let 分配也可能分配给默认成员 - 并且默认成员调用是隐式的,而且非常混乱确实。

    这与您在 Excel VBA 中分配单元格值时完全相同:

    Dim r As Range
    Set r = ActiveSheet.Range("A1")
    

    Dim r As Double
    r = ActiveSheet.Range("A1") 'implicit call to ActiveSheet.Range("A1").[_Default]
    

    这两个指令看起来不同,只是因为一个有Set关键字而另一个没有,但真正的区别是对隐藏属性的隐式成员调用 命名为[_Default],具有VB_UserMemId = 0 属性,该属性使该成员成为类的默认成员

    混淆源于隐式默认成员调用,它使代码某些东西,而实际上别的东西。

    Rubberduck(我管理的一个 OSS VBIDE 插件项目)有一个代码检查,可以定位早期绑定代码中的隐式默认成员分配:

    隐式默认成员分配

    这样的赋值看起来像是在表面上将对象变量分配给值类型,但实际上它们是隐式地分配该对象的默认成员。考虑显式引用默认成员,以提高可读性。

    【讨论】:

    • @Nicholas - 好了,我告诉过你,有人会很快发布比我更深入的答案......这个只花了“–14 秒”。现在那就是快了。
    • @ashleedawg 实际上,我查看了代码,它与隐式默认成员分配无关 - 简单地说,该函数返回一个可能包含值或对象的 Variant参考。分配引用需要Set,...仅此而已。尽管如此,我猜还是很高兴知道隐式默认成员分配 =)
    • @MathieuGuindon 谢谢!哦,现在我明白了,因为如果解析器需要解析 JSON 对象/数组,它需要使用必须是 Set 的 Dictionary/Collection 来保存它。对于其他情况(JSON 整数/字符串/布尔值/等),返回的变量是原始的,不能是 Set
    • @ashleedawg :D 我仍然非常想阅读您的 JSON 解析器实现。不久前我几乎自学了 C++ 和一些数据结构,但我每天都使用 VBA,所以用 VBA 更深入地学习 CS 是有意义的(但是无法访问 C/C++ 指针确实让我烦恼)。跨度>
    【解决方案2】:

    您所指的三种类型是dictionarycollectionarray。基本上,这些的任何组合都可以构成一个 JSON 结构。

    有更多时间的人可能会给出更好的答案,但它的要点是(在我过于简化的解释中),

    • 将值分配给变量会生成该值的副本

    • Set 用于对象,因为它不是复制对象,而是创建对象的引用

    通常,当您使用 Set 将对象引用分配给变量时,不会为该变量创建对象的副本。相反,会创建对该对象的引用。 多个对象变量可以引用同一个对象。因为这些变量是对对象的引用而不是对象的副本,所以对象的任何变化都会反映在所有引用的变量中它。但是,当您在 Set 语句中使用 New 关键字时,您实际上是在创建对象的 instance(Source)


    更多信息:

    【讨论】:

    • 我稍后会扩展,但我需要重新开始工作,巧合的是我自己的基于 Excel 的 JSON 解析器形式,因为我从来都不是 VBA-JSON 的粉丝。跨度>
    • 感谢您的回复!我现在明白了 Set= 之间的区别。让我困惑的是,为什么作者在需要解析 JSON 对象/数组时使用 Set?我要删除它,看看会发生什么。顺便问一下,你不喜欢 VBA-JSON 的原因是什么?
    猜你喜欢
    • 2014-10-26
    • 1970-01-01
    • 1970-01-01
    • 2011-03-22
    • 2015-02-10
    • 2017-05-28
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    相关资源
    最近更新 更多