我想我最近(终于)开始了解ByVal
和ByRef
如何在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
VB Array
在传递ByVal时会引发编译器错误,可能是对此的警告
所有这些让我思考:
ByVal
和ByRef
之间有什么区别(如果有的话)Boolean
,Long
)可以通过ByVal
从类和类型不能VB6
编写的东西
是否可以使用默认的ByVal
响应创建对象?
在Python中,您可以指定类对不同关键字的反应。我怀疑你能否在VBA中做到这一点,但是用一种更通用的语言编写的对象可以说,检测它是否通过ByVal
并返回自己的.Clone
。
换句话说,VBA的内置数据类型如何通过qazxswpoi传递,并且任何其他对象都可以模仿这种行为(同样,在Python中,一切都是对象,因此可以复制所有行为*)。或者我不必担心这种情况会发生吗?
是否有可能模仿ByVal
的行为并在传递Array
时引发编译器错误 - 因为数组没有克隆方法而且不能轻易复制所以总是ByVal
*轶事,我是Python的新手
在我迄今为止所经历的所有教程和参考文献中,ByRef总是“传递对象”,ByVal是“传递对象的副本”。
你有上述例子的链接吗?
ByRef
就像ByVal
,而*foo
就像ByRef
。**foo
就像ByVal
,而bar
就像ByRef
。*bar
或ByRef
。
VBA“内置”数据类型在C / C ++中具有类似物,因此ByVal
是32位整数,因此实际上是Long
但是只能取两个值中的一个(0 = False,-1 = True)。你不用担心,VBA在安全名称中设置了限制。
如果要强制为对象传递Boolean
,则创建一个Type而不是一个类。ByRef
才能复制类型。数组和类型通过=
传递,因为它们是在堆栈上创建的。
对于VBA中的对象和类,传递byval或byref没有实际区别。传递byref ony意味着指针传递'byref',对象保持不变。
如果你想到它,它对(Excel)对象有意义;无论你传递范围(“A1”)byref还是byval,它仍然是我们正在处理的同一个单元格。