例如,在PHP中我们可以这样写:
class C {
var $x;
function __construct($x) {
$this->x = $x;
}
function __toString() {
return (string)$this->x;
}
}
function f1($obj) {
$obj->x = 2;
}
$a = new C(1);
f1($a);
echo $a; // 2
有些人会说这表明对象是通过引用传递的,因为您可以修改它们的属性,并且这些更改会反映在类之外。即,对象不会以原语的方式复制。
但是我们可以写下这个:
function f2($obj) {
$obj = new C(2);
}
$b = new C(1);
f2($b);
echo $b; // 1
现在建议该对象根本不通过引用传递。实际上,对象被复制(即通过值传递)但不是深 - 复制; $obj
已被复制,但$x
仍指同一件事。
我听说“参考”这个词曾经意味着两种方式;有人会说PHP是通过引用传递的,有些人会说传递值。
如果我们说PHP是通过引用传递的,那么在定义像
这样的函数时我们的意思是什么function f3(&$obj)
? 那个函数对一个对象进行引用,这表明第一个意思是错误的。
但那么像C ++这样的语言和C#中的结构呢?我的C ++有点生疏,但我相信整个类在传递它时实际上会被深层复制,这就是为什么鼓励你的函数在可能的情况下使用引用,或使用指针。在C#中,结构和类之间的区别在于它们如何通过。
如果不按值传递,您称之为深度复制行为是什么?
似乎我们有3个行为,只有两个短语来描述它们,这在社区中造成了很多混乱。
哎呀,我只是在等你们其中一个人告诉我,我在这里写错了。
总之,这三种行为是:
从技术上讲,我们应该将这些行为称为什么?传递通过 - ???
答案 0 :(得分:2)
首先要做的事情:您可能想阅读References Explained。
通常,变量总是按值传递。重要的是价值实际上是什么。
如果变量“持有一个对象”,它将持有对象的引用。
因此,当你有一个像
这样的函数定义时function foo($bar) {}
传递对象的引用。这就是你可以改变对象的原因。
但是如果你为函数内部的变量赋一个新值,那么你只是用其他东西覆盖了引用,你就失去了对象的引用。
假设您传递给函数的变量$someVar
,$bar
和$someVar
将具有相同的值(即引用),但它们在存储器中。
在:
$someVar -> object_reference ┐
├ -> object
$bar -> object_reference ┘
后:
$someVar -> object_reference -> object
$bar -> other_value
现在,如果函数定义类似于
function foo(&$bar) {}
然后你实际上传递了一个引用到内存中某个其他变量的位置。
如果您使用foo($someVar)
调用此函数,$bar
将指向与$someVar
相同的位置,即如果您指定了新值,则会覆盖内存中的特定位置
在:
$someVar ┐
├ -> object_reference -> object
$bar ┘
后:
$someVar ┐
├ -> other_value object
$bar ┘
答案 1 :(得分:1)
如果我有我的druthers,.net中的术语“对象引用”将被替换为类似“object-id”的东西,以明确在大多数情况下将对象传递给例程时,object-id是按值传递的(尽管在某些情况下,例如Dictionary.TryGetValue,其中object-id通过引用传递)。使用相同的术语来描述对象id和一种参数传递会导致混淆。
答案 2 :(得分:1)
在C ++中,前两个都被称为pass-by-value。深层复制的深度取决于所讨论的类的复制语义,它可以并且应该由程序员指定(某些类是资源的句柄,必须浅层复制;其他类,如大多数容器,必须深-copied)。 Python具有用于深度和浅层复制的库函数。深度复制有时称为克隆,尤其是克隆。在C ++和Java中。
第三个被称为传递参考。这是传递可以被被调用者就地修改的东西的通用术语。
(C是这个约定的一个例外,因为它没有引用的概念,但是pass-by-pointer几乎与pass-by-reference相同。)
答案 3 :(得分:0)
您必须区分两件事:对变量的引用和对象的引用。只要您不为参数$ obj指定其他值,就会处理与函数外部完全相同的对象。在为其分配了另一个对象之后,变量已经更改,但由于您只传递了对象的引用而没有传递给变量,因此外部的变量仍未触及指向原始对象...