Groovy与Python函数参数传值传引用区分及堆栈分配规则疑问
结论先行
你的核心猜测(Groovy、Python本质全是按值传递)是对的,但你把现象归因于「栈/堆分配差异」是错的,这个和内存存储位置没有关系,是语言的传参语义+对象可变性共同导致的差异。
核心语义解释
Groovy(基于JVM)和Python的参数传递统一遵循**按对象引用传值(也叫传共享pass-by-sharing)**规则,属于纯按值传递的一种实现:
- 这两门语言中所有变量本质都是「对象的引用」,不存在C语言中直接存储值的栈变量
- 函数传参时,永远会把实参的引用值拷贝一份传给形参,形参和实参是两个独立的引用,指向同一个对象
- 两门语言都不支持真正的按引用传递:你无法通过修改函数形参的指向来改变外部实参的指向,这也是你给形参重新赋值不会影响外部变量的根本原因。
你的代码运行结果的原因
字典修改外部可见的原因
你调用dfunc(my_dict)时:
- 形参
v和外部的my_dict是两个独立的引用,指向同一个字典对象 - 执行
v.foo = "dolor"时,你是通过引用修改了指向的对象本身的内容,所以外部的my_dict指向同一个对象,自然能看到修改 - 后续执行
v = [a:"a", b:"b"]时,你只是修改了形参v这个引用本身的指向,让它指向了一个新的字典对象,完全不会影响外部my_dict的指向,所以外部的my_dict还是原来的对象,只是属性被修改了
整数修改外部不可见的原因
你调用podfunc(my_int)时:
- 整数是不可变对象,语言层面不允许修改整数对象本身的内容
- 执行
v = 42时,你只是把形参v的引用指向了新的整数对象42,完全碰不到外部my_int的引用,所以外部的my_int还是指向原来的5
关于栈堆分配的疑问
栈/堆分配是语言运行时的底层实现细节,和上层的传参语义没有绑定关系:
- Groovy、Python都是托管运行的语言,内存分配由运行时自动管理,开发者不需要、也没有语法可以直接控制变量的存储位置
- 即使是对象类型,只要满足运行时的优化条件(比如JVM的逃逸分析判定对象没有逃出当前作用域),也可能被分配在栈上,完全不会影响上层的传参表现
- 你看到的两个
def声明没有差异,是因为这两门语言的语法层面本来就没有暴露栈分配的相关概念,所有变量都是对象引用,存储位置完全由运行时动态决定。
内容的提问来源于stack exchange,提问作者StoneThrow
相关产品推荐
相关产品推荐

