首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如果在Ruby中,这一切都是一个对象,为什么这不起作用呢?

如果在Ruby中,这一切都是一个对象,为什么这不起作用呢?
EN

Stack Overflow用户
提问于 2011-10-07 14:06:04
回答 5查看 10.9K关注 0票数 12

考虑到在Ruby编程语言中,所有的东西都被认为是一个对象,我认为将参数传递给方法是通过引用来完成的。然而,下面这个小小的例子让我感到困惑:

代码语言:javascript
复制
$string = "String"

def changer(s)
  s = 1
end

changer($string)

puts $string.class
String
 => nil

正如您所看到的,原始对象没有被修改,我想知道为什么是,以及我如何才能完成期望的行为,即。获取方法来实际更改其参数所引用的对象.

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-10-07 14:22:26

Ruby的工作方式是按值传递和通过引用传递的组合。实际上,Ruby在引用中使用pass值。

您可以在以下线程中阅读更多内容:

  • Pass by reference or pass by value
  • Pass by reference?

一些值得注意的引语是:

绝对正确: Ruby带有引用。

:004:0> def foo(x) x= 10 => nil irb(main):005:0> def bar;x= 20;foo(x);x end => nil irb(main):006:0> bar => 20 irb(main):007:0>

在调用作用域中,没有任何标准的方法(例如,除了涉及eval和元编程魔术)使变量指向另一个对象。而且,顺便说一句,这与变量引用的对象无关。Ruby中的直接对象与其他对象无缝集成(例如,与Java中的POD不同),从Ruby语言的角度来看,您不会看到任何不同(除了性能之外)。这就是为什么Ruby如此优雅的原因之一。

向方法传递参数时,传递指向引用的变量。在某种程度上,它是由值传递和引用传递的组合。我的意思是,将变量的值传递给方法,但是变量的值始终是对对象的引用。

以下两者之间的区别:

my_method( A) a.gsub!( /foo/,'ruby‘)结束str = 'foo是可怕的’my_method( str ) #=> 'ruby是可怕的‘str #=> 'ruby是可怕的’

以及:

def your_method( A)a= a.gsub( /foo/,'ruby‘)结束str = 'foo是可怕的’my_method( str ) #=> 'ruby‘str #=> 'foo是可怕的’

在#my_method中,您正在调用#gsub!它改变了已到位的对象(a)。因为'str‘变量(在方法范围之外)和'a’变量(在方法范围内)都有一个“值”,即对同一个对象的引用,因此在调用方法之后,对该对象的更改将反映在'str‘变量中。在#your_method中,调用#gsub不修改原始对象。相反,它创建一个包含修改的字符串的新实例。当您将该对象赋值给“a”变量时,您将“a”的值更改为对该新字符串实例的引用。但是,'str‘的值仍然包含对原始(未修改的)字符串对象的引用。

方法是否更改引用或引用对象取决于类类型和方法实现。

代码语言:javascript
复制
string = "hello"

def changer(str)
  str = "hi"
end

changer(string)
puts string
# => "hello"

string不会更改,因为字符串上的赋值替换引用,而不是引用值。如果你想修改字符串的位置,你需要使用String#replace

代码语言:javascript
复制
string = "hello"

def changer(str)
  str.replace "hi"
end

changer(string)
puts string
# => "hi"

String是一种常见的情况,大多数操作都在克隆上工作,而不是在self实例上工作。出于这个原因,有几个方法有一个执行相同操作的bang版本。

代码语言:javascript
复制
str1 = "hello"
str2 = "hello"

str1.gsub("h", "H")
str2.gsub!("h", "H")

puts str1
# => "hello"
puts str2
# => "Hello"

最后,要回答原来的问题,您不能更改字符串。您只能给它分配一个新值,或者将字符串包装到一个不同的可变对象中,并替换内部引用。

代码语言:javascript
复制
$wrapper = Struct.new(:string).new
$wrapper.string = "String"

def changer(w)
  w.string = 1
end

changer($wrapper)

puts $wrapper.string
# => 1
票数 24
EN

Stack Overflow用户

发布于 2011-10-07 14:23:44

赋值不将值绑定到对象,而是将对象引用绑定到标识符。参数传递的工作方式也是一样的。

当您输入函数的主体时,世界如下所示:

代码语言:javascript
复制
 +---+                  +----------+
 | s |----------------->| "String" |
 +---+                  +----------+
                              ^
 +-------+                    |
 |$string|--------------------+
 +-------+

密码

代码语言:javascript
复制
 s = 1

让世界看起来像

代码语言:javascript
复制
 +---+       +---+      +----------+
 | s |------>| 1 |      | "String" |
 +---+       +---+      +----------+
                              ^
 +-------+                    |
 |$string|--------------------+
 +-------+

赋值语法操纵变量,而不是对象。

与许多类似的语言(Java、C#、Python)一样,ruby是按值传递的,其中的值通常是引用的。

若要操作string对象,可以在字符串上使用方法,例如s.upcase!。这类事情将反映在方法之外,因为它操作对象本身。

票数 17
EN

Stack Overflow用户

发布于 2011-10-07 14:16:57

因为$strings都是对同一个对象的引用,所以字符串" string“。但是,当您将s分配给1时,您不会更改对象"String",而是让它引用一个新对象。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7688391

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档