我昨天遇到了这个问题,想知道按值传递、按引用传递和按值传递引用的关系是什么。他们的行为如何?哪种编程语言使用哪种?
另外:我也偶尔听到过其他术语,如 pass-by-pointer、pass-by-copy、pass-by-object ......它们是如何适应的?
我昨天遇到了这个问题,想知道按值传递、按引用传递和按值传递引用的关系是什么。他们的行为如何?哪种编程语言使用哪种?
另外:我也偶尔听到过其他术语,如 pass-by-pointer、pass-by-copy、pass-by-object ......它们是如何适应的?
这是一个虚构的术语,指的是实际上是按值传递的东西,但人们总是会感到困惑,因为语言中唯一的值是引用(指向事物的指针)。许多现代语言都以这种方式工作,包括 Java(用于非原始语言)、JavaScript、Python、Ruby、Scheme、Smalltalk 等。
初学者总是在 StackOverflow 上问为什么它不是 pass-by-reference,因为他们不明白 pass-by-reference 到底是什么。因此,为了让他们满意,一些人编造了一个他们也不理解的新术语,但让人觉得他们学到了一些东西,听起来有点像 pass-by-value 和 pass-by-reference 。
不同语言社区之间的术语使用差异很大。例如,Java 社区几乎总是将此语义描述为按值传递,而 Python 和 Ruby 社区很少将其描述为按值传递,即使它们在语义上是相同的。
让我们从基础开始。你可能已经知道这一点,或者至少认为你知道。令人惊讶的是,许多人实际上都在滥用这些术语(这当然无助于混淆)。
我现在不打算告诉你答案,而是用例子来解释它。稍后你会明白为什么。
想象一下,您正在尝试学习一种编程语言,而一位朋友告诉您他知道一本关于该主题的好书。你有两个选择:
案例 1:如果您借他的书并在页边空白处做笔记(并添加一些书签、参考资料、图纸……),您的朋友以后也可以从这些笔记和书签中受益。分享是关怀。世界真好!
案例 2:但是,另一方面,如果您的朋友有点爱整洁,或者非常珍惜他的书,他可能不会欣赏您的笔记,更不用说偶尔的咖啡渍或您如何折叠角落以添加书签。你真的应该得到你自己的书,每个人都可以愉快地以他喜欢的方式对待他的书。世界真好!
这两种情况——你猜对了——就像传递引用和传递值一样。 区别在于函数的调用者是否可以看到被调用者所做的更改。
让我们看一个代码示例。假设您有以下代码片段:
function largePrint(text):
text = makeUpperCase(text)
print(text)
myText = "Hello"
largePrint(myText)
print(myText)
并且您以按值传递的语言运行它,输出将是
HELLO
Hello
而在传递参考语言中,输出将是
HELLO
HELLO
如果您通过引用传递,则变量“myText”会被函数更改。如果您只是传递变量的值,则函数无法更改它。
如果你需要另一个例子,这个使用网站的例子得到了很多支持。
好的,现在我们已经掌握了基础知识,让我们继续...
让我们再次使用我们的书籍示例。假设您决定向您的朋友借这本书,尽管您知道他是多么喜欢他的书。让我们也假设你当时——作为一个完全的笨蛋——把一加仑咖啡洒在上面。哦,我的……别担心,你的大脑会启动并意识到你可以给你的朋友买一本新书。状态如此之好,他甚至都不会注意到!
这个故事与按值传递引用有什么关系?
好吧,另一方面,想象一下你的朋友非常喜欢他的书,他不想借给你。然而,他确实同意把这本书带来给你看。问题是,你仍然可以将一加仑咖啡洒在上面,但现在你不能再给他买一本新书了。他会注意到的!
虽然这听起来很可怕(并且可能让你像喝了那加仑咖啡一样出汗),但它实际上很常见并且是共享书籍调用功能的完美方式。它有时被称为按值传递引用。
代码示例的表现如何?
在按值传递引用的函数中,我们的代码片段的输出是
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 使用按值传递引用!(Java、Ruby 和 Scheme 也是如此……)
这非常困难吗?不,那为什么这么多人对此感到困惑?(我不会链接到关于“如何在 Python 中通过引用传递变量”或“Java 是否通过引用传递?”等所有其他问题......)
好吧,我看到几个原因:
如果您认为我应该添加任何内容,请告诉我。如果我犯了错误,请告诉我!