我想我最近(终于)开始了解 ByValByRef 在 VBA 中的工作方式。

观察

在我迄今为止所经历的所有教程和引用文献中,ByRef 总是“传递对象”,ByVal 总是“传递对象的副本”。对我来说,后者意味着对象在内存中的位置被复制,并返回一个指向该新位置的指针。我现在意识到情况并非总是如此,事实上据我所知,这种情况很少发生:相反,大多数对象和类实际上都传递了 ByRef,即使在例程的签名中指定了 ByVal
System.Collections.ArrayList 以 ByRef 静默方式传递,如以下代码所示:

Sub test()
    Dim list1 As Object, list2 As Object
    Set list1 = CreateObject("System.Collections.ArrayList")
    list1.Add "foo"
    Set list2 = RemoveItem(list1)
    Debug.Assert list2.Contains("foo") = False 'as expected
    Debug.Assert list1.Contains("foo") = True  'raises error, meaning list1 was passed byref not byval
End Sub

Function RemoveItem(ByVal list As Object) As Object 'ByVal
    list.Remove "foo" 'expect to remove from a copy and return that
    Set RemoveItem = list
End Function

考虑到我对 ByVal 的了解,这让我感到惊讶。进一步挖掘告诉我,要从 ByVal 获得我想要的副本,我需要传递的对象具有启用此功能的方法。对于 ArrayList.Clone 方法进行浅拷贝。所以我的功能变成:
Function RemoveItem(ByRef list As Object) As Object 'ByRef or ByVal, makes no difference
    Dim listCopy As Object
    Set listCopy = list.Clone 'make a shallow copy of the object
    listCopy.Remove "foo" 'actually remove from a copy and return that
    Set RemoveItem = listCopy
End Function

当传递 ByVal 时,VB Array 会引发编译器错误,这可能是针对此的警告

问题

这一切让我想到:
  • 类/对象的 ByValByRef 之间有什么区别(如果有)
  • 什么区分了某些类型( BooleanLong ),这些类型可以从不能
  • 的类和类型中传递 ByVal
  • 在库引用方面 - 可能不会用 VB6 编写的东西
  • 是否可以创建具有默认 ByVal 响应的对象?
  • 在 Python 中,您可以指定类对不同关键字的 react 方式。我怀疑您是否可以在 VBA 中 native 做到这一点,但是用更通用的语言编写的对象是否可以说,检测它是否正在传递 ByVal 并返回自身的 .Clone
  • 换句话说,VBA 的内置数据类型如何通过 ByVal 以及任何其他对象是否可以模仿这种行为(同样,在 Python 中,一切都是对象,因此一切行为都可以复制*)。或者我不必担心这种情况会发生吗?
  • 是否有可能模仿 Array 的行为并在传递 ByVal 时引发编译器错误 - 因为数组没有克隆方法并且不能容易地复制所以总是 ByRef
  • 是否有一个 Sub、Function 或方法可以让我创建对象的深拷贝?也就是说,复制一个对象使用的内存并创建对象的第二个副本的通用方法。

  • *轶事,我对 Python 很陌生

    最佳答案



    你有上面例子的链接吗?

  • 对于对象(从类创建) ByVal 就像 *fooByRef 就像 **foo
  • Boolean 和 Long 是原语,对于原语 ByVal 就像 barByRef 就像 *bar
  • 没有
  • 对象无法判断它是否已通过 ByRefByVal
  • VBA“内置”数据类型在 C/C++ 中有类似物,因此 Long 是一个 32 位整数,Boolean 实际上也是,但只能取两个值之一(0=False,-1=True)。您不用担心,VBA 以安全的名义进行了限制。
  • 如果你想强制传递 ByRef 给你的对象,那么创建一个 Type 而不是一个类。
  • 对于类,您必须编写自己的浅层和深层复制构造函数。但是类型可以通过使用 = 无论是浅的还是深的来复制。

  • 数组和类型被传递 ByRef 因为它们是在堆栈上创建的。

    关于excel - ByVal 是谎言吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49845406/

    10-13 09:54