请问Julia
语言中有没有像C/C++
中的函数参数地址引用
Julia的变量是对某个值的绑定,是“引用语义”的,这和C/C++有显著不同。
int a=1; //a表示一块在内存中的大小为sizeof(int)的区域,是值语义的
int b=a; //b复制了a的值
而在Julia当中
a=MyType() #a是对一个MyType类型的值的引用
b=a #现在b和a绑定到了同一个值上
因此Julia的变量之间赋值天生就是“传引用”的,函数调用同理。但是,对于isbitstype
类型来说(类似C/C++的基本类型),它们是不可变的,并且它们里面也没有字段,所以你没有办法把这样的类型传给函数里面然后修改它。(事实上,由于isbits
变量不可变,两个Int
类型的值1
和1
,只要数字是一样的,它们之间毫无区别,因此引用不引用的已经无关紧要了,编译器给你编译出来的可能就是立即数操作的机器码,根本不涉及堆内的对象。)
a=1 #Int(1)是isbits且不可变的
b=a
a=2 #这只是让a指向了另一个值,b不会受到任何影响
但是你可以把不可变的值放在可变的容器里,比如数组:
julia> a=[1,2,3]
3-element Array{Int64,1}:
1
2
3
julia> function mutate!(x)
push!(x,4)
end
mutate! (generic function with 1 method)
julia> mutate!(a);
julia> a
4-element Array{Int64,1}:
1
2
3
4
通过在函数内部直接修改a
指向的那个数组,你就可以在函数内部对外部造成副作用。
在和C/C++代码交互的时候,可以把值放在Ref
里面,它代表对某一个值的引用,且它位于一块稳定的内存里,你可以拿到它的指针,然后传给C/C++的函数:
julia> x=Ref(0) #x指向一个Int(0)的Ref,你可以拿到这块内存的地址
Base.RefValue{Int64}(0)
julia> using Cxx
C++ > void mutate(int64_t* p){
*p=42;
}
true
julia> ptr=Base.unsafe_convert(Ptr{Int64},x)
Ptr{Int64} @0x000000000ff32fe0
julia> @cxx mutate(ptr)
julia> x[] #解引用,获得Ref的内容
42
即使一个类型是不可变的,但它拥有可变的成员,你也可以通过引用修改它的内容:
julia> struct ImmutableType
x
end
julia> u=ImmutableType(Ref(1))
ImmutableType(Base.RefValue{Int64}(1))
julia> v=u
ImmutableType(Base.RefValue{Int64}(1))
julia> v.x[]=2
2
julia> u.x[]
2
这里的不可变指的是,你无法修改ImmutableType里的字段x,使x指向另一个对象(例如v.x=Ref(3)
),并不代表整个对象所在的内存是只读的。
题外话:
可变对象有点类似C/C++的左值概念,你可以拿到可变对象的稳定的内存地址,这同时也会阻止一些优化措施,因此条件允许的情况下应该优先使用不可变对象。可变类型之间的相等判定===
是比较内存地址,而不可变类型之间的相等默认则是比较它们的值。如果一个类型是不可变的,又没有成员,那么它就是个单例,即
julia> struct Singleton end
julia> Singleton()===Singleton()
true
1 个赞