一个数组同时拥有多个变量名的意义在哪?(注意语义)

  a=b=c=[0]
  x=y=z=0    # 与统一赋值很像

同样语法暗藏着似乎相反的语义。不搞清楚,就会踩坑。

这不是坑,是feature。你除了C之外难道没写过点别的语言么…Java C# Python Ruby啥的都行

Julia的变量从来就不是值语义,变量是可以绑定到值的名字(引用),变量之间的赋值从来都是让它们指向同一个东西。

只不过0作为bits类型Int的实例,是immutable的,所以

x = 0 #x指向Int类型的对象Int(0)
y = x #y和x指向同一个东西
x = 1 #x指向另一个Int类型的对象Int(0)
y #还是0

你无法通过修改Int对象来对y施加影响。

对于immutable的东西,只要内容是一样的,它们就是一样的(in the sense that no program could
distinguish them),虽然immutable赋值的具体实现可能只是一个mov指令

julia> 0===0
true

julia> struct S
           x
       end

julia> S(0)===S(0)
true

julia> mutable struct M
           x
       end

julia> M(0)===M(0)
false

但是,[0]是Array,Array是mutable类型,所以

x = [0]
y = x #x和y指向同一个Array对象,并不是复制
x[1] = 1
y #y[1] == 1

所以,还是那句话,多看文档……

5 个赞

这么说的话,Julia中的标识和值是分离的吗

本来抛砖引玉,结果又是半砣砖砸到我自己:grin:
谈语言本身,正如:“坑” 是指“面上看不见,藏在下面的”一样。解释只是附加说明而已。
按题目,意义何在?茴香豆的回吗?
避免冗余和歧义,也是语言所追求的。

BTW,除了C 还有perl
#!/usr/bin/perl
use strict;
use warnings;

my @a=(10,20,30);
my @b=@a;

$a[1]=5;

print “a=@a\nb=@b\n”;
#--------------
结果:
a=10 5 30
b=10 20 30

另外,与其它语言争议较多的“数组0,1开头问题”反倒是个嘘头,没有争议的价值。

我记得动态语言不能控制复制时是传值还是传引用,在c中数组的话是一个数组两个变量名,其实就是指向同一个地址,c++可以通过拷贝构造函数控制,其他语言我就不知道,大概就是语言特性吧

还是变量语义的问题,C/C++的普通变量是值语义的,变量表示的是内存位置,比如

int x = 0;

它表示一个自动变量,是左值,在生存期内拥有稳定的内存位置,可以被寻址。
对比Julia,

x = 0

这里的x只是一个名字,当前绑定到了某个Int对象上(甚至它自身都是没有类型的,有类型的是值),x并不代表内存位置,因此你无法取地址,也不能作为ccall的输出参数。

再看看C++的STL,它从行为上也是模拟了值语义,因此

vector<int> v = { 1,2,3 };
vector<int> v_copy = v; // 复制了一份,看起来和基本类型一样
vector<int>& v_ref = v; // 引用指向v
vector<int>* v_ptr = &v; //指针指向v

使用operator=直接赋值,会发生对象复制。如果你需要引用语义,则需要使用“引用”(C++术语)或者“指针”来实现。对于指针而言,它自身也是值语义的普通变量,访问所指需要进行解引用。

语言的基本设计都是不一样的,因此看起来不一样的表达式具有不同的含义,使用之前必须想清楚。

避免冗余和歧义,也是语言所追求的。

完全没有歧义,只是你不熟。

如果你在Julia里需要v_copy行为,那么需要显式进行复制:

a = [1,2,3]
b = copy(a)

我记得动态语言不能控制复制时是传值还是传引用

动态语言和传值传引用没有关系。你说的“复制”可能是指“=”的含义,这个不同语言都有自己的约定。

例如C#是静态类型语言(没错,静态类型系统和垃圾回收之间也没有任何联系),但是C#的class类型表现为引用语义,基本变量和struct类型表现为值语义。

在c中数组的话是一个数组两个变量名

这是啥?

那个,声明一个数组a,然后b=a,b和a都是这个数组的别名,这个意思
传值传引用好像体现在函数传参那一部分

int a[] = { 1,2,3 };
int* b = a;

你说这个吗?a是一个int[3]数组,而b是一个int*指针,赋值的时候发生了隐式类型转换,数组a退化成了&a[0],即首元素指针。以上代码的效果是b指向了a的首地址。

两个数组之间是无法赋值的。

只是举个例子与上面的perl语句区别开来

你的意思是 “看起来一样的表达式具有不同的含义”吧?“使用之前必须想清楚”意思是避免歧义吧?

意思是不要认为看起来一样的东西能生搬硬套到其他语言里去

在一个语言内部没有歧义

语言歧义不只指内部没有歧义;而是语法面上不会导致歧义。

搞了半天,还是没有回答题目问题。
一个数组同时拥有多个变量名的意义在哪?

所以题目问题是什么?

a=b=c=[0]
a[1]= 1 会修改 b, c 指向的内容
a = [1] 不会修改 b, c

看心情,你要他们分离的话就copy:yum:

搞了半天,还是没有回答题目问题。
一个数组同时拥有多个变量名的意义在哪?

上面的解释已经很明确了
如果你要问意义,你可以先说说C指针的意义和C++ shared_ptr的意义在哪

你说的都没错。其实讨论点在值语义和引用语义的选择上。这应当在教程简介的特色中阐述的,但基本上都不在那个地方明确讲。

通俗一点,一个是给变量赋值;一个是给值取名。

这两个语义一个是为了避免引用管理繁琐和不经意的bug;一个是为了节约内存。一个趋向人性化,一个趋向机器化。

这两个语义又不是不能共存。。在julia中immutable的类型是值语义,其他类型是引用语义,这有什么歧义吗?

1 个赞

是个折衷方案。用的时候得考虑清楚。

所以你的意思是要么全都是值语义,要么全都是引用语义吗?
或者像cpp一样严格区分,*&用起来吗,抱歉你说了这么多我还是不明白你想表达的意思。