什么是传递参考值?

时间:2013-06-04 23:20:07

标签: parameter-passing pass-by-reference pass-by-value

昨天我遇到了这个问题,并且想知道传值,传递参考和传递参考的关系是什么。他们都表现得怎么样?哪种编程语言使用哪种?

此外: 我偶尔也会听到其他术语,如传递指针,传递副本,传递对象......它们如何适应?

2 个答案:

答案 0 :(得分:1)

这是一个虚构的术语,指的是实际上是按值传递的东西,但人们总是感到困惑,因为语言中唯一的值是引用(指向事物的指针)。许多现代语言以这种方式工作,包括Java(用于非原语),JavaScript,Python,Ruby,Scheme,Smalltalk等。

初学者总是在StackOverflow上询问有关为什么它不是通过引用传递的问题,因为他们不明白传递的是什么传递。因此,为了满足他们,一些人构成了一个他们也不理解的新术语,但使他们看起来像是学到了什么,而且听起来有点像传值和传递参考。

术语的使用在不同语言社区之间差异很大。例如,Java社区几乎总是将这种语义描述为值传递,而Python和Ruby社区很少将其描述为按值传递,即使它们在语义上是相同的。

答案 1 :(得分:0)

让我们从基础开始。你可能已经知道这个或者至少认为你这样做了。令人惊讶的是,很多人实际上都在滥用这些术语(这对于混淆肯定没有帮助)。

什么是按值传递和按引用传递?

我现在还没有告诉你答案,而是用例子来解释。你会在以后看到原因。

想象一下,你正在尝试学习一门编程语言,而一位朋友告诉你,他知道一本关于这个主题的好书。您有两种选择:

  1. 从他那里借书或
  2. 购买自己的副本。
  3. 案例1:如果你借阅他的书并在边缘做笔记(并添加一些书签,参考文献,图纸......),你的朋友以后也可以从这些笔记和书签中受益。分享是关怀。世界太棒了!

    案例2:但另一方面,如果你的朋友有点整洁,或者非常珍惜他的书,他可能不会欣赏你的笔记,甚至更少偶尔的咖啡渍或你如何折叠书签的角落。你应该得到自己的书,每个人都可以按自己喜欢的方式愉快地对待他的书。世界太棒了!

    这两种情况 - 你猜对了 - 就像传递引用和传值一样。 区别在于函数的调用者是否可以看到被调用者所做的更改。

    让我们看一下代码示例。 假设您有以下代码段:

    function largePrint(text):
      text = makeUpperCase(text)
      print(text)
    
    myText = "Hello"
    largePrint(myText)
    print(myText)
    

    然后用值传递语言运行它,输出将是

    HELLO
    Hello
    

    而在传递参考语言中,输出将是

    HELLO
    HELLO
    

    如果你通过引用传递变量" myText"由功能改变。如果您只是传递变量的值,则函数无法更改它。

    如果你需要另一个例子,this一个使用网站的人得到了不少赞成。

    好的,既然我们已经掌握了基础知识,那就让我们继续......

    什么是pass-reference-by-value?

    让我们再次使用我们的书籍例子。假设你已经决定从朋友那里借这本书,虽然你知道他有多喜欢他的书。让我们假设你 - 然后就是你的总klutz - 在它上面洒了一加仑咖啡。天啊... 不用担心,你的大脑启动并意识到你可以给你的朋友买一本新书。它处于如此良好的状态,甚至没有注意到!

    这个故事与传递参考值有什么关系?

    好吧,另一方面,想象一下你的朋友非常喜欢他的书,他并不想把它借给你。但他确实同意带这本书给你看。问题是,你仍然可以将一加仑咖啡洒在上面,但现在你不能再为他买一本新书了。他会注意到的!

    虽然这可能听起来很可怕(并且可能让你大汗淋漓,好像你已经喝了那加仑咖啡一样)但实际上它很常见并且是一种非常好的方法来<打击>分享书籍来电功能。它有时被称为pass-reference-by-value。

    代码示例如何运作?

    在pass-reference-by-value函数中,我们的代码段的输出是

    HELLO
    Hello
    

    就像传值的情况一样。但是如果我们稍微改变一下代码:

    function largePrint(text):
      text.toUpperCase()
      print(text)
    
    myText = "Hello"
    largePrint(myText)
    print(myText)
    

    输出变为:

    HELLO
    HELLO
    

    就像传递参考案例一样。原因与书中的例子相同:我们可以通过调用text.toUpperCase()(或通过在其上溢出咖啡)来更改变量(或书)。但是我们不能再改变变量引用的对象(text = makeUppercase(text)没有效果);换句话说,我们不能使用不同的书。

    总结我们得到:

    通过按值:

    您可以获得自己的书籍,自己的变量副本以及原始所有者永远不会知道的任何内容。

    通过按引用:

    您使用与朋友相同的书或与调用者相同的变量。如果您更改了变量,它将在您的函数之外更改。

    通过引用按值

    你和朋友一样使用同一本书,但他并没有让它离开他的视线。您可以更改书籍但不能更换书籍。在变量术语中,这意味着您无法更改变量引用,但您可以更改变量引用的

    现在,当我向您展示以下Python代码时:

    def appendSeven(list):
        list.append(7)
    
    def replaceWithNewList(list):
        list = ["a", "b", "c"]
    
    firstList = [1, 2, 3, 4, 5, 6]
    print(firstList)
    appendSeven(firstList)
    print(firstList)
    
    secondList = ["x", "y", "z"]
    print(secondList)
    replaceWithNewList(secondList)
    print(secondList)
    

    告诉你输出是这个

    [1, 2, 3, 4, 5, 6]
    [1, 2, 3, 4, 5, 6, 7]
    ['x', 'y', 'z']
    ['x', 'y', 'z']
    
    你怎么说?

    确实,你是对的! Python使用pass-reference-by-value! (Java和Ruby以及Scheme也是如此......)

    结论:

    这是非常困难的吗?没有。 那么为什么这么多人会被它迷惑呢? (我不会链接到关于&#34的所有其他问题;我如何通过Python中的引用传递变量&#34;或者#34; Java是否通过引用传递?&#34;等等......)

    嗯,我看到了几个原因:

    1. 说通过引用传递值真的很长(并且它的行为几乎与传递引用相同,所以得到我的背部并停止分裂头发!)
    2. 有令人讨厌的特殊情况使问题复杂化
      • 类似于原始类型(通常是按引用值引用语言中的值传递)
      • 不可变类型(不能更改,因此通过引用传递它们并不能让你到任何地方)
    3. 有些人喜欢使用不同的名字:
      • 传递副本 按值传递,因为如果你注意了,你需要自己的书,所以必须制作副本。 (但这是一个实现细节,像写时复制这样的其他技巧可能只用于制作副本。)
      • 传递引用 传递引用按值因为,毕竟,您确实获得了引用,这意味着您可以更改对象来电者(即使你不能改变它)
      • 传递引用 传递引用按值,因为几乎没有语言实际上有传递引用(值得注意的例外(我知道): C ++,C#但你必须使用特殊的语法)
      • 传递分享 传递参考值(还记得我们的书籍示例吗?这个名字实际上更好,每个人都应该使用它!)< / LI>
      • 传递对象 传递参考值因为据称Barbara Liskov首先将其命名并使用它,因此它的birthname)
      • 传递指针 传递引用,因为C没有传递引用,这就是它允许您完成的方式同样的事情。
    4. 如果您认为我应该添加任何内容,请告知我们。如果我弄错了,请让我知道!

      对于那些仍然没有足够的人:http://en.wikipedia.org/wiki/Evaluation_strategy