“参考”的使用方式是不是有歧义?
Posted
技术标签:
【中文标题】“参考”的使用方式是不是有歧义?【英文标题】:Is there ambiguity in the way "reference" is used?“参考”的使用方式是否有歧义? 【发布时间】:2011-06-12 03:11:21 【问题描述】:例如,在 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
这表明对象根本不是通过引用传递的。实际上,对象被复制(即,按值传递)但不是deep-复制的; $obj
被复制了,但 $x
仍然指的是同一个东西。
我听说“参考”这个词过去有两种意思;有人会说 PHP 是按引用传递,也有人会说是按值传递。
如果我们说 PHP 是通过引用传递的,那么定义一个类似的函数是什么意思
function f3(&$obj)
? 那个函数引用一个对象,这表明第一个意思是错误的。
但是对于像 C++ 这样的语言和 C# 中的结构呢?我的 C++ 有点生疏,但我相信整个类在传递它时实际上会被深度复制,这就是为什么鼓励你的函数尽可能使用引用或使用指针的原因。在 C# 中,结构和类的传递方式有所不同。
如果不是按值传递,你怎么称呼这种深度复制行为?
似乎我们有 3 种行为,只有两个短语来描述它们,这在社区中造成了很多混乱。
哎呀,我只是在等你们中的一个告诉我我在这里写错了。
总的来说,这三种行为是:
-
对象被深度复制(对象及其属性被克隆)
仅复制对象(其属性仍引用同一块内存)
对象根本没有被复制
从技术上讲,我们应该如何称呼这些行为?路过-???
【问题讨论】:
有一天(或者可能不会),PHP 将为参数实现const
关键字,这将消除任何歧义... :)
【参考方案1】:
您必须区分两件事……对变量的引用和对对象的引用。只要您不为参数 $obj 分配其他值,您就可以处理与函数外部完全相同的对象。在为它分配另一个对象后,变量发生了变化,但是由于您只传递了对该对象的引用而不是变量的引用,因此外部的变量仍然没有被触及,指向您的原始对象......
【讨论】:
【参考方案2】:如果我有我的 druthers,.net 中的“对象引用”一词将被“object-id”之类的东西取代,以明确在大多数情况下,当一个对象被传递给例程时,object-id按值传递(尽管在某些情况下,例如 Dictionary.TryGetValue,其中 object-id 通过引用传递)。使用相同的术语来描述 object-id 和参数传递的类型会导致混淆。
【讨论】:
【参考方案3】:在 C++ 中,前两个都称为按值传递。深度复制的深度取决于所讨论类的复制语义,程序员可以并且应该指定它(一些类是资源句柄,必须是浅复制的;其他类,例如大多数容器,必须是深复制的) -复制)。 Python 具有用于深复制和浅复制的库函数。深度复制有时被称为克隆,尤其是。在 C++ 和 Java 中。
第三种称为按引用传递。这是传递可以由被调用者就地修改的东西的通用术语。
(C 是这个约定的一个例外,因为它没有引用的概念,但指针传递与引用传递几乎相同。)
【讨论】:
【参考方案4】:第一件事:您可能想阅读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 ┘
【讨论】:
那么......然后回答这个问题。你说,什么?对象是通过对对象的引用 传递的,而在另一种情况下,您是通过对内存中位置的引用?那么原始人呢?还是深度复制的对象?您在两种情况下都使用了“参考”一词,因此您同意,除非完全限定,否则存在歧义? @Mark:Imo 这个词没有歧义。在这两种情况下使用该术语是正确的,因为它们描述了相同的概念。如果参数未使用&
符号定义,您永远不会说函数接受引用。你知道,如果你传递对象,你可以修改它们的属性。请注意,在第二个示例中,您没有对传递的对象的属性进行操作,而是为变量分配了一个新值。引用只是唯一定义其他事物的事物。您会在其他 OO 语言中发现相同的行为。
@Mark:对不起,如果我不能以更容易理解的方式解释它。
不,我想我明白你的意思。在这个意义上,“参考”一直被使用,但是“通过参考传递”这个短语不是。这可能意味着......哦,算了吧。我了解幕后发生的事情,这只是愚蠢的措辞。我认为我们应该将 & 号的情况称为“别名”。以上是关于“参考”的使用方式是不是有歧义?的主要内容,如果未能解决你的问题,请参考以下文章