language-agnostic - 按引用传递与按值传递有什么区别?

标签 language-agnostic pass-by-reference pass-by-value

之间有什么区别

  • 通过引用
  • 传递的参数
  • 通过值传递的参数?

  • 请给我一些例子吗?

    最佳答案

    首先,在CS理论中定义的“按值传递vs.按引用传递”的区别现在已过时,因为最初被定义为“按引用传递”的技术已不受欢迎,并且很少使用现在1

    较新的语言2倾向于使用另一对(但相似)的技术来达到相同的效果(请参见下文),这是造成混淆的主要原因。

    造成混淆的第二个原因是,“通过引用传递”,“引用”中的的含义比通用术语“引用” 的含义要窄(因为该短语早于它)。

    现在,真实的定义是:

  • 当参数由引用传递时,调用方和被调用方使用相同的变量作为参数。如果被调用者修改了参数变量,则效果对调用者的变量可见。
  • 当参数通过值传递时,调用方和被调用方具有两个独立变量,它们具有相同的值。如果被调用方修改了参数变量,则该效果对调用方不可见。

  • 在此定义中要注意的是:
  • 这里的“变量”表示调用方的(本地或全局)变量本身,即,如果我通过引用传递局部变量并将其分配给它,则我将更改调用方的变量本身,而不是例如无论它指向的是什么指针。
  • 现在认为这是不良做法(作为隐式依赖项)。因此,实际上是所有较新的语言都是专有的或几乎专有的按值传递。 现在,在函数不能返回多个值的语言中,按引用传递主要以“输出/输入参数”的形式使用。
  • 在“按引用传递” 中“引用”的含义。与一般“参考”一词的区别在于这个“参考”是临时的和隐式的。 被调用者基本上得到的是,它是一个与原始变量“相同”的“变量”。 这种效果的具体实现方式是不相关的(例如,该语言可能还公开了一些实现细节-地址,指针,取消引用-都是不相关的;如果最终效果是,则是按引用传递)。


  • 现在,在现代语言中,变量倾向于是“引用类型” (另一种概念是在“按引用传递”之后发明并受其启发),即,实际的对象数据分别存储在某个位置(通常在堆上) ,并且只有对其的“引用”才会保存在变量中并作为参数传递。3

    传递此类引用属于按值传递,因为从技术上讲变量的值是引用本身,而不是引用的对象。但是,对程序的实际影响可以与按值传递或按引用传递相同:
  • 如果引用只是从调用者的变量中获取并作为参数传递的,则与传递引用具有相同的效果:如果所引用的对象在被调用者中发生了更改,则调用者将看到更改。
  • 但是,如果重新获得了保存此引用的变量,它将停止指向该对象,因此对该变量进行的任何进一步操作都会影响它现在指向的内容。
  • 要与传递值具有相同的效果,请在某个时候制作对象的副本。选项包括:
  • call 者可以在 call 之前制作一个私有(private)副本,然后给被 call 者一个引用。
  • 在某些语言中,某些对象类型是“不可变的”:对它们进行的任何更改其值的操作实际上都会创建一个全新的对象,而不会影响原始对象。因此,将这样类型的对象作为参数传递始终具有按值传递的效果:如果需要更改,当需要更改时,将自动为被调用方创建一个副本,并且调用方的对象永远不会受到影响。
  • 在功能语言中,所有对象都是不可变的。

  • 如您所见,这对技术与定义中的技术几乎相同,只是有一定程度的间接性:只需将“变量”替换为“引用对象”即可。

    它们没有统一的名称,这导致了诸如“按值调用,其中值是引用”的错误解释。 1975年,芭芭拉·里斯科夫(Barbara Liskov)提出了“call-by-object-sharing”一词(有时也称为“按共享 call ”),尽管该词从未流行。而且,这两个短语都没有与原始短语相似。难怪旧术语最终会在没有更好的东西的情况下被重用,从而导致混乱。4

    注意:很长一段时间以来,这个答案曾经说过:

    Say I want to share a web page with you. If I tell you the URL, I'm passing by reference. You can use that URL to see the same web page I can see. If that page is changed, we both see the changes. If you delete the URL, all you're doing is destroying your reference to that page - you're not deleting the actual page itself.

    If I print out the page and give you the printout, I'm passing by value. Your page is a disconnected copy of the original. You won't see any subsequent changes, and any changes that you make (e.g. scribbling on your printout) will not show up on the original page. If you destroy the printout, you have actually destroyed your copy of the object - but the original web page remains intact.



    除“引用”的狭义含义外,这基本上是正确的-它既是临时的又是隐式的(不是必须的,但显式和/或持久的是附加功能,而不是“按引用传递”语义的一部分) ,如上所述)。更为贴近的类比是给您一份文档副本,而不是邀请您使用原始文档。

    1除非您使用Fortran或Visual Basic进行编程,否则这不是默认行为,并且在现代使用的大多数语言中,甚至不可能进行真正的按引用调用。

    2相当多的老年人也支持它

    3在几种现代语言中,所有类型都是引用类型。这种方法由1975年的CLU语言首创,此后被包括Python和Ruby在内的许多其他语言采用。还有更多的语言使用混合方法,其中一些类型是“值类型”,而其他类型是“引用类型”-其中包括C#,Java和JavaScript。

    4回收一个合适的旧词本身没有什么不好,但是必须以某种方式弄清楚每次使用的含义。不这样做正是造成混乱的原因。

    关于language-agnostic - 按引用传递与按值传递有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63326454/

    相关文章:

    debugging - 如何重现偶尔发生的错误?

    java - 当内存不足引发 OutOfMemoryError 时会发生什么?

    string - 如何找到至少重复一次的字符串中的最大序列?

    algorithm - 返回数组中最多的元素个数 "expensive"

    c++ - 按值传递参数和按引用传递参数有什么区别?

    c++ - 提供按值和按引用都可用的函数版本

    javascript - 通过引用 javascript 中的函数来循环遍历数组

    c - 函数什么时候必须通过引用接收参数才能改变参数的某些内容?

    c++ - 当通过引用传递成为强制通过地址/指针传递时

    c++ 引用 - 是否分配了内存?