ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 1146|回复: 6

[原创] 传址和传值 (byref,byval)

[复制链接]

TA的精华主题

TA的得分主题

发表于 2021-6-20 16:47 | 显示全部楼层 |阅读模式
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 hyefeifei 于 2021-6-20 16:58 编辑

简单讲讲传址与传值,错漏之处望大家指正补充。
一:
传址,即把参数在内存中的地址传给子程序。
测试代码:
  1. Sub ref_val()
  2. Dim r          As Integer
  3. Dim dblarea    As Double
  4.     r = 10
  5.     calcarea r   '传址,参数r变化
  6.     Debug.Print "半径 =" & r
  7. End Sub
  8. '此函数传址
  9. Function calcarea1(ByRef radius As Integer) As Double
  10.     radius = radius ^ 2
  11.     calcarea = Application.Pi() * radius
  12. End Function
复制代码
运行到:calcarea r,子程序会按地址在内存中寻找到r,然后对r平方处理,运行debug.print "半径=“ & r ,会发现r值已经变为100。
二:
传值,会在内存找一个新地址复制参数值,把这个新地址传给子程序,子程序的操作,不会改变原地址中的值(即不会改变原参数的值)。
测试代码:
  1. Sub ref_val()
  2. Dim r          As Integer
  3. Dim dblarea    As Double
  4.     r = 10
  5.     calcarea r    '传值,参数r无变化
  6.     Debug.Print "半径 =" & r
  7. End Sub
  8. '此函数传值
  9. Function calcarea(ByVal radius As Integer) As Double
  10.     radius = radius ^ 2
  11.     calcarea = Application.Pi() * radius
  12. End Function
复制代码
运行到:calcarea r,子程序会去新地址找复制的值,然后进行操作,原参数值不会受影响,运行debug.print "半径=“ & r ,会发现r值仍为10。

TA的精华主题

TA的得分主题

 楼主| 发表于 2021-6-20 16:54 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 hyefeifei 于 2021-6-20 17:02 编辑

三:
强制传值,如果我们在调用子程序时,把参数加上括号,此时,参数会按传值处理,即子程序的传址无效。
测试代码:
  1. Sub ref_val()
  2. Dim r          As Integer
  3. Dim dblarea    As Double
  4.     r = 10
  5.     calcarea1 (r)     '强制传值,参数r无变化
  6.     Debug.Print "半径 =" & r
  7. End Sub

  8. '此函数传址
  9. Function calcarea1(ByRef radius As Integer) As Double
  10.    radius = radius ^ 2
  11.    calcarea1 = Application.Pi() * radius
  12. End Function
复制代码
运行至Debug.Print "半径 =" & r,仍然输出10,因调用子程序时,参数加括号,强制传值了。
注意,当我们使用 call calcarea1(r)调用参数时,并没有强制传值,只有我们使用call calcarea1((r))调用参数时,才是强制传值。

TA的精华主题

TA的得分主题

发表于 2021-6-20 17:11 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
例行顶帖   感谢分享

TA的精华主题

TA的得分主题

 楼主| 发表于 2021-6-20 17:18 | 显示全部楼层
四:
数组,当我们把数组做为参数传给子程序时,只能传址,传值会提示错误。
测试代码:
  1. Sub arr_ref_val()
  2.     Dim arr(1 To 2)
  3.     arr(1) = 10.5
  4.     arr(2) = 15.3
  5.     calcint arr
  6.     Debug.Print arr(1), arr(2)
  7. End Sub

  8. '参数为数组,只能传址
  9. Function calcint(ByRef a())
  10.     Dim i          As Long
  11.     For i = LBound(a) To UBound(a)
  12.         a(i) = Int(a(i))
  13.     Next i
  14.     calcint = a
  15. End Function
复制代码
运行到 Debug.Pring arr(1),arr(2)时,会输出 10 15,因数组参数按址传递,原值已经改变。

TA的精华主题

TA的得分主题

 楼主| 发表于 2021-6-20 17:23 | 显示全部楼层
五:
数组传值,如果我们不想改变原数组,可以在子程序中把参数做为Variant变量传递,此时可以传值。
  1. Sub arr_ref_val()
  2.     Dim arr(1 To 2)
  3.     arr(1) = 10.5
  4.     arr(2) = 15.3
  5.     calcint arr
  6.     Debug.Print arr(1), arr(2)
  7. End Sub

  8. '参数为variant数据类型,可以传值
  9. Function calcint(ByVal a As Variant)
  10.     Dim i          As Long
  11.     For i = LBound(a) To UBound(a)
  12.         a(i) = Int(a(i))
  13.     Next i
  14.     calcint = a
  15. End Function
复制代码
运行主程序,可以看到输出值为10.5 15.3,没有变化,此时数组已强制按值传递。

TA的精华主题

TA的得分主题

 楼主| 发表于 2021-6-20 18:13 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 hyefeifei 于 2021-6-21 08:30 编辑

六:
字典,对于字典来说,如果子程序没有重新实例化参数,则传址和传值都会改变原参数。
测试代码:
  1. Sub testDict()
  2.     Dim d          As Dictionary
  3.     Dim i          As Long
  4.     Dim arr
  5.     Set d = New Dictionary
  6.     d("a") = 2
  7.     d("b") = 10
  8.     pDict d
  9.     arr = d.Items
  10.     For i = LBound(arr) To UBound(arr)
  11.         Debug.Print arr(i)
  12.     next i
  13. End Sub
  14. '虽然是传值方式传递参数,但是原字典还是会被改变
  15. Function pDict(ByVal odc As Dictionary)
  16.     odc("c") = 100
  17. End Function
复制代码


运行主程序,会看到输出了 2 10 100,说明原参数已经被改变,虽然参数是按值传递的,如果子程序参数按byref传递参数,结果相同。

如果我们在子程序中重新实例化了对象会是什么结果?
  1. Function pDict(ByVal odc As Dictionary)
  2.     Set odc = New Dictionary '重新实例化对象
  3.     odc("c") = 100
  4. End Function
复制代码
可以看出,参数是按值传递的,此时会在内存中另一个地址生成一个字典,然后添加一个 100,原字典并没有被触碰,主程序输出为 2 10。
  1. Function pDict(ByRef odc As Dictionary)
  2.      Set odc = New Dictionary '重新实例化对象
  3.      odc("c") = 100
  4. End Function
复制代码
可以看出,参数是按地址传递的,此时会在内存中原字典地址生成一新字典,原字典被覆盖,主程序输出为 100

对于集合(collection),应该与字典情况相同,其他情况没做测试,欢迎大家补充。








评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2022-9-14 22:25 | 显示全部楼层
很不错的分享,有学习到不错的点
最后,字典传值并且重新实例化,感觉有点不可思议
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-5-2 02:55 , Processed in 0.039067 second(s), 11 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表