Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么可以使用另一种方法而不是赋值运算符在函数中更改Ruby中局部变量的值?_Ruby_Variables_Pass By Reference_Pass By Value - Fatal编程技术网

为什么可以使用另一种方法而不是赋值运算符在函数中更改Ruby中局部变量的值?

为什么可以使用另一种方法而不是赋值运算符在函数中更改Ruby中局部变量的值?,ruby,variables,pass-by-reference,pass-by-value,Ruby,Variables,Pass By Reference,Pass By Value,我试图理解Ruby作为传递引用值语言的概念。使用我在网站上找到的一个例子 我们得到了输出。所以value和name都指向同一个对象,该对象最初持有一个William值,然后upcase将其更改为William。我会理解为通过参考 但如果我将.upcase改为=: 输出变为William。这是通过值传递的 为什么赋值运算符会对Ruby中变量的处理方式产生影响?这里的关键是,您永远不能更改Ruby对象的核心自我,一旦创建了它,它将始终是同一个对象,直到垃圾被收集和销毁。只能更改对象的属性 但是,您可

我试图理解Ruby作为传递引用值语言的概念。使用我在网站上找到的一个例子

我们得到了输出。所以value和name都指向同一个对象,该对象最初持有一个William值,然后upcase将其更改为William。我会理解为通过参考

但如果我将.upcase改为=:

输出变为William。这是通过值传递的


为什么赋值运算符会对Ruby中变量的处理方式产生影响?

这里的关键是,您永远不能更改Ruby对象的核心自我,一旦创建了它,它将始终是同一个对象,直到垃圾被收集和销毁。只能更改对象的属性

但是,您可以更改变量或对象引用,例如实例变量、常量、attr_访问器属性等

因此,在这种情况下:

def uppercase2(value)
  value = "WILLIAM"
end
这将重新分配局部变量的值。它对原始对象没有任何影响

如果要替换该文本,需要使用对象上的方法来实现它(如果支持)。在这种情况下,有一种方法:

def uppercase2(value)
  value.replace("WILLIAM")
end

这些通常被称为就地修改,因为对象本身是被操纵的,而不是被另一个对象交换。

这里的关键是,你永远不能改变Ruby对象的核心自我,一旦它被创建,它将始终是同一个对象,直到垃圾被收集和销毁。只能更改对象的属性

但是,您可以更改变量或对象引用,例如实例变量、常量、attr_访问器属性等

因此,在这种情况下:

def uppercase2(value)
  value = "WILLIAM"
end
这将重新分配局部变量的值。它对原始对象没有任何影响

如果要替换该文本,需要使用对象上的方法来实现它(如果支持)。在这种情况下,有一种方法:

def uppercase2(value)
  value.replace("WILLIAM")
end

这些通常被称为就地修改,因为对象本身是被操纵的,而不是被另一个对象交换。

让我们开始用更容易理解的方式来分解它

您可以将名称或值等变量与路标进行比较

假设我把它指向a米色房子,这将是变量的值

请记住上面的第一个例子:

# don't worry about this line for now
House = Struct.new(:color)
在这里,我们从同样的开始,复制我们的路标房子,并将副本赋值。然而,我们不是走到房子前面去粉刷它,而是要修改路标,把它指向街上更远的某个地方的一栋红房子。因为我们的路标价值是房子的复制品,将它指向一个新的方向不会影响房子

你的代码也在做同样的事情。当您调用value.upcase时!你是在对她说绳子。嘿,你,把你所有的角色都翻过来!类似于粉刷房子


当您重新设计value=WILLIAM时,实际上您只是在修改路标并将其指向一个新的方向。但是,路标是作为副本传递的,因此不会影响原始路标。

让我们开始用更容易理解的方式将其分解

def uppercase(value)
  value.upcase!
end

name = 'William'
uppercase(name)
puts name #WILLIAM
您可以将名称或值等变量与路标进行比较

假设我把它指向a米色房子,这将是变量的值

请记住上面的第一个例子:

# don't worry about this line for now
House = Struct.new(:color)
在这里,我们从同样的开始,复制我们的路标房子,并将副本赋值。然而,我们不是走到房子前面去粉刷它,而是要修改路标,把它指向街上更远的某个地方的一栋红房子。因为我们的路标价值是房子的复制品,将它指向一个新的方向不会影响房子

你的代码也在做同样的事情。当您调用value.upcase时!你是在对她说绳子。嘿,你,把你所有的角色都翻过来!类似于粉刷房子

当您重新设计value=WILLIAM时,实际上您只是在修改路标并将其指向一个新的方向。但是,路标作为副本传递,因此不会影响原件

def uppercase(value)
  value.upcase!
end

name = 'William'
uppercase(name)
puts name #WILLIAM
在本例中,您正在对原始对象进行变异。名字指向威廉 价值也是如此。当您传入参数时,Ruby将赋值 名称指向的同一对象的参数变量值

def uppercase2(value)
  value = "WILLIAM"
end

name = 'William'
uppercase2(name)
puts name
在这种情况下,您正在重新分配值。也就是说,你正在改变哪一个 对象值指向。它指向的字符串对象与 我的名字指的是。但是,现在,您要求的是引用a的值 不同的对象

所以,总而言之,是厄普凯斯!在=将重新分配时对对象进行变异。 你可以想到3个圆圈,一个圆圈中有值,另一个圆圈中有名字,还有威廉 在第三节。 value和name都指向string对象William

在第一种情况下,你变异了stri ng同时包含值和名称的对象 你指的是什么

def uppercase2(value)
  value = "WILLIAM"
end

name = 'William'
uppercase2(name)
puts name
在第二种情况下,您将创建第四个圆圈,其中包含WILLIAM。然后,您将删除从value到William的行,并创建一行 从价值到威廉

如果我这样做,你就会明白:

def uppercase2(value)
  value = "WILLIAM"
  puts value
end

name = 'William'
uppercase2(name) # => “WILLIAM”
puts name           # William
在本例中,您正在对原始对象进行变异。名字指向威廉 价值也是如此。当您传入参数时,Ruby将赋值 名称指向的同一对象的参数变量值

def uppercase2(value)
  value = "WILLIAM"
end

name = 'William'
uppercase2(name)
puts name
在这种情况下,您正在重新分配值。也就是说,你正在改变哪一个 对象值指向。它指向的字符串对象与 我的名字指的是。但是,现在,您要求的是引用a的值 不同的对象

所以,总而言之,是厄普凯斯!在=将重新分配时对对象进行变异。 你可以想到3个圆圈,一个圆圈中有值,另一个圆圈中有名字,还有威廉 在第三节。 value和name都指向string对象William

在第一种情况下,您将对同时包含值和名称的字符串对象进行变异 你指的是什么

def uppercase2(value)
  value = "WILLIAM"
end

name = 'William'
uppercase2(name)
puts name
在第二种情况下,您将创建第四个圆圈,其中包含WILLIAM。然后,您将删除从value到William的行,并创建一行 从价值到威廉

如果我这样做,你就会明白:

def uppercase2(value)
  value = "WILLIAM"
  puts value
end

name = 'William'
uppercase2(name) # => “WILLIAM”
puts name           # William
我试图理解Ruby作为传递引用值语言的概念

Ruby是按值传递的。总是它永远不会被引用。正在传递的值是一个不可变的不可格式化指针,但这与按引用传递非常不同

C是传递值。C有指针。这并不意味着如果在C中传递指针,它会神奇地变成按引用传递。它仍然是按价值传递的

C++有指针,它支持按值传递和按引用传递。在C++中,可以通过值或引用传递指针,可以通过值或引用传递非指针。这两个概念是完全正交的

如果我们可以同意C是按值传递的,我们可以同意C有指针,我们可以同意当我们在C中传递指针时,它仍然是按值传递的,那么我们还必须同意Ruby是按值传递的,因为Ruby的行为就像C的一个假设版本,其中唯一允许的类型是指向某个对象的指针,访问值的唯一方法是取消对指针的引用,传递值的唯一方法是使用指针

这不会以任何方式改变在C中传递的参数,这意味着它仍然是通过值传递的,这意味着如果我们在C中调用它,那么在Ruby中调用它是没有意义的

我们得到了输出。所以value和name都指向同一个对象,该对象最初持有一个William值,然后upcase将其更改为William。我会理解为通过参考

同样,这不是通过引用传递的。passbyreference意味着您可以更改调用方作用域中的引用,而Ruby不允许您这样做

这只是简单的突变。Ruby不是一种纯粹的函数式语言,它允许您改变对象。当你改变一个对象时,你可以观察它的变化状态,不管你叫它什么名字

我的朋友叫我约格,但我的理发师叫我米塔格先生。当我的理发师给我理发时,当我遇到我的朋友时,我的头发不会神奇地长回来,即使他们对我的称呼与我的理发师不同,我的头发也会消失

同一个对象有两个名称,然后对该对象进行变异。无论使用哪个名称引用该对象,都将观察新状态

这只是可变状态,与按引用传递无关

但如果我将.upcase改为=:

输出变为William。这是通过值传递的

为什么赋值运算符在Ruby中处理变量的方式上会有所不同

没有。这两种情况都是按值传递的。在第二种情况下,您创建了一个新对象,并将其指定给uppercase2方法中的局部变量值。从技术上讲,它不是一个局部变量,它是一个参数绑定,但它可以在方法体中反弹,这正是因为Ruby是按值传递的。如果它是通过引用传递的,那么这也会将名称局部变量重新分配给新创建的对象

有时,这种传递值的特定情况(传递的值是指向潜在可变对象的不可变指针)称为逐对象调用共享、逐共享调用或逐对象调用。但这与传递值没有什么不同。它仍然是按价值传递的。这是值传递的一种特殊情况,其中值不能是任何值,但始终是不可变的不可伪造指针

有时,您会听到这样的描述:Ruby是按值传递的,其中传递的值是引用,或者Ruby是按引用传递的值,或者Ruby是按值传递的引用,或者Ruby是按对象传递的- 参考我真的不喜欢这些术语,因为它们听起来非常接近通过引用,但实际上通过引用中的术语引用和通过对象引用中的术语引用是指两种不同的东西

在传递引用中,术语引用是一个技术术语,可以被认为是变量、存储位置等概念的概括。在传递值引用中,我们谈论的是对象引用,它更像指针,但不能被制造或更改

我也不喜欢上面使用的术语“按值传递”,其中传递的值是一个不可变的不可伪造指针,因为指针这个术语有一定的含义,特别是对于来自C语言的人来说。在C语言中,你可以做指针算术,你可以向指针投射一个数字,也就是说,你可以凭空变出一个指针。在Ruby中,这些都做不到。这就是为什么我要加上形容词“不可变的,没有算术的,不可伪造的”你不能创建一个指针,只能被系统交给一个,但是人们忽视或忽视了它们,或者低估了它们的重要性

在某些语言中,这些指向对象的不可变不可伪造指针被称为对象引用,这同样是危险的,因为它会引起与按引用传递或面向对象指针的混淆,而面向对象指针的不幸含义是几乎不受限制的所有C指针都是自由的。例如,Go有更多限制性的指针,但是当你简单地说单词pointer时,没有人想到Go

请注意,这些都不是Ruby特有的。Python、ECMAScript、Java和许多其他语言的行为方式都相同。默认情况下,C的行为方式相同,但也支持通过引用传递作为显式的opt-in。您必须在方法定义和方法调用时显式请求按引用传递。Scala默认情况下的行为方式相同,但可以选择支持按名称调用

事实上,C是一种很好的方式来证明这些区别,因为C支持按值传递和按引用传递,同时支持值类型和引用类型,而且很明显,您可以将类型同时作为可变类型和不可变类型来编写,因此您实际上可以获得所有8种可能的不同组合,并且可以研究它们的行为

我提出了这个简单的测试代码,您也可以轻松地将其翻译成其他语言:

def是通过值传递的吗?foo 更准确地说,它是由对象共享调用的 foo='不,Ruby是通过引用传递的。' 终止 bar='是的,当然,Ruby*是*传递值!' 是通过值传递的吗 p条 “更准确地说,它是由对象共享调用的!” :

结构可变单元格{公共字符串值;} 静态void ArgumentPassingstring[]foo,可变单元格条,参考字符串baz,参考可变单元格qux { foo[0]=更准确地说,对于引用类型,它由对象共享调用,这是传递值的一种特殊情况。; foo=新字符串[]{C不是通过引用传递的。}; bar.value=对于值类型,它是*非*共享调用。; bar=新的可变单元格{value=也不通过引用传递。}; baz=如果明确请求,它还支持按引用传递。; 值类型也支持qux=new MutableCell{value=Pass by reference.}; } var qux=新字符串[]{Yes,当然,C*是*传递值!}; var corge=new MutableCell{value=对于值类型,它是纯传递值。}; var grault=由于引用传递,此字符串将消失。; var garply=new MutableCell{value=由于引用传递,此字符串将消失。}; 辩论通过权、科奇、格劳特、加普利; Console.writelinequeux[0]; //更准确地说,对于引用类型,它由对象共享调用,这是传递值的一种特殊情况。 Console.WriteLinecorge.value; //对于值类型,它是纯传递值。 Console.WriteLinegrault; //如果显式请求,它还支持按引用传递。 Console.WriteLinegarply.value; //值类型也支持按引用传递。 我试图理解Ruby作为传递引用值语言的概念

Ruby是按值传递的。总是它永远不会被引用。正在传递的值是一个不可变的不可格式化指针,但这与按引用传递非常不同

C是传递值。C有指针。这并不意味着如果在C中传递指针,它会神奇地变成按引用传递。它仍然是按价值传递的

C++有指针,它支持按值传递和按引用传递。在C++中,可以通过值或引用传递指针,可以通过值或引用传递非指针。这两个概念是完全正交的

如果我们可以同意C是按值传递的,我们可以同意C有指针,我们可以同意当我们在C中传递指针时,它仍然是按值传递的,那么我们还必须同意Ruby是按值传递的,因为Ruby的行为类似于C的假设版本,其中 ed类型是指向某个对象的指针,访问值的唯一方法是取消对指针的引用,传递值的唯一方法是使用指针

这不会以任何方式改变在C中传递的参数,这意味着它仍然是通过值传递的,这意味着如果我们在C中调用它,那么在Ruby中调用它是没有意义的

我们得到了输出。所以value和name都指向同一个对象,该对象最初持有一个William值,然后upcase将其更改为William。我会理解为通过参考

同样,这不是通过引用传递的。passbyreference意味着您可以更改调用方作用域中的引用,而Ruby不允许您这样做

这只是简单的突变。Ruby不是一种纯粹的函数式语言,它允许您改变对象。当你改变一个对象时,你可以观察它的变化状态,不管你叫它什么名字

我的朋友叫我约格,但我的理发师叫我米塔格先生。当我的理发师给我理发时,当我遇到我的朋友时,我的头发不会神奇地长回来,即使他们对我的称呼与我的理发师不同,我的头发也会消失

同一个对象有两个名称,然后对该对象进行变异。无论使用哪个名称引用该对象,都将观察新状态

这只是可变状态,与按引用传递无关

但如果我将.upcase改为=:

输出变为William。这是通过值传递的

为什么赋值运算符在Ruby中处理变量的方式上会有所不同

没有。这两种情况都是按值传递的。在第二种情况下,您创建了一个新对象,并将其指定给uppercase2方法中的局部变量值。从技术上讲,它不是一个局部变量,它是一个参数绑定,但它可以在方法体中反弹,这正是因为Ruby是按值传递的。如果它是通过引用传递的,那么这也会将名称局部变量重新分配给新创建的对象

有时,这种传递值的特定情况(传递的值是指向潜在可变对象的不可变指针)称为逐对象调用共享、逐共享调用或逐对象调用。但这与传递值没有什么不同。它仍然是按价值传递的。这是值传递的一种特殊情况,其中值不能是任何值,但始终是不可变的不可伪造指针

有时,您会听到这样的描述:Ruby是按值传递的,其中传递的值是引用,或者Ruby是按引用传递的值,或者Ruby是按值传递的引用,或者Ruby是按对象传递的引用。我真的不喜欢这些术语,因为它们听起来非常接近通过引用,但实际上通过引用中的术语引用和通过对象引用中的术语引用是指两种不同的东西

在传递引用中,术语引用是一个技术术语,可以被认为是变量、存储位置等概念的概括。在传递值引用中,我们谈论的是对象引用,它更像指针,但不能被制造或更改

我也不喜欢上面使用的术语“按值传递”,其中传递的值是一个不可变的不可伪造指针,因为指针这个术语有一定的含义,特别是对于来自C语言的人来说。在C语言中,你可以做指针算术,你可以向指针投射一个数字,也就是说,你可以凭空变出一个指针。在Ruby中,这些都做不到。这就是为什么我要加上形容词“不可变的,没有算术的,不可伪造的”你不能创建一个指针,只能被系统交给一个,但是人们忽视或忽视了它们,或者低估了它们的重要性

在某些语言中,这些指向对象的不可变不可伪造指针被称为对象引用,这同样是危险的,因为它会引起与按引用传递或面向对象指针的混淆,而面向对象指针的不幸含义是几乎不受限制的所有C指针都是自由的。例如,Go有更多限制性的指针,但是当你简单地说单词pointer时,没有人想到Go

请注意,这些都不是Ruby特有的。Python、ECMAScript、Java和许多其他语言的行为方式都相同。默认情况下,C的行为方式相同,但也支持通过引用传递作为显式的opt-in。您必须在方法定义和方法调用时显式请求按引用传递。Scala默认情况下的行为方式相同,但可以选择支持按名称调用

事实上,C是一种很好的方式来证明这些区别,因为C支持按值传递和按引用传递,同时支持值类型和引用类型,而且很明显,您可以将类型同时作为可变类型和不可变类型来编写,所以您实际上可以得到所有8种可能的不同组合,并且可以研究它们是如何 大街

我提出了这个简单的测试代码,您也可以轻松地将其翻译成其他语言:

def是通过值传递的吗?foo 更准确地说,它是由对象共享调用的 foo='不,Ruby是通过引用传递的。' 终止 bar='是的,当然,Ruby*是*传递值!' 是通过值传递的吗 p条 “更准确地说,它是由对象共享调用的!” :

结构可变单元格{公共字符串值;} 静态void ArgumentPassingstring[]foo,可变单元格条,参考字符串baz,参考可变单元格qux { foo[0]=更准确地说,对于引用类型,它由对象共享调用,这是传递值的一种特殊情况。; foo=新字符串[]{C不是通过引用传递的。}; bar.value=对于值类型,它是*非*共享调用。; bar=新的可变单元格{value=也不通过引用传递。}; baz=如果明确请求,它还支持按引用传递。; 值类型也支持qux=new MutableCell{value=Pass by reference.}; } var qux=新字符串[]{Yes,当然,C*是*传递值!}; var corge=new MutableCell{value=对于值类型,它是纯传递值。}; var grault=由于引用传递,此字符串将消失。; var garply=new MutableCell{value=由于引用传递,此字符串将消失。}; 辩论通过权、科奇、格劳特、加普利; Console.writelinequeux[0]; //更准确地说,对于引用类型,它由对象共享调用,这是传递值的一种特殊情况。 Console.WriteLinecorge.value; //对于值类型,它是纯传递值。 Console.WriteLinegrault; //如果显式请求,它还支持按引用传递。 Console.WriteLinegarply.value; //值类型也支持按引用传递。
经验法则是你永远不能改变自己。如果value=WILLIAM确实发生了变异,那实际上是在改变self的值,对吗?因此,这是不可能的,Ruby会重新分配变量。经验法则是你永远不能改变自己。如果value=WILLIAM确实发生了变异,那实际上是在改变self的值,对吗?因此这是不可能的,Ruby重新分配了变量……或者值[0..-1]=WILLIAM。我被你想说的话弄糊涂了。你的第一句话是你永远不能更改Ruby对象,然后在你的第二个代码段中,你演示了如何更改一个对象,这似乎与你的第一句话直接矛盾。@JörgWMittag我的意思是你不能更改对象本身,它的基本自我,就像在object_id中一样,但你可以更改对象属性,就像字符串的内容……或值[0..-1]=WILLIAM。我被你想说的话弄糊涂了。你的第一句话是你永远不能更改Ruby对象,然后在你的第二个代码段中,你演示了如何更改一个对象,这似乎与你的第一句话直接矛盾。@JörgWMittag我的意思是你不能更改对象本身,它的基本自我,就像在object_id中一样,但你可以更改对象属性,就像字符串的内容一样。