我不明白为什么他们说 Ruby按值传递所有参数,同时下面的代码证明了相反的情况:
class MyClass1
@var1 = 123
def get1
@var1
end
def set1=value
@var1 = value
end
end
c1 = MyClass1.new
c1.set1 = 444
p c1.get1 # 444
def test1 mc
mc.set1 = 999
end
test1 c1
p c1.get1 # 999
Run Code Online (Sandbox Code Playgroud)
如果按价值计算,它会打印出来444,而不是999.
考虑到在Ruby编程语言中,一切都被称为对象,我安全地假设将参数传递给方法是通过引用完成的.然而,下面这个小例子让我困惑:
$string = "String"
def changer(s)
s = 1
end
changer($string)
puts $string.class
String
=> nil
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,原始对象未被修改,我希望知道为什么,以及如何实现所需的行为,即.获取方法实际更改其参数引用的对象.
根据模块和类的文档,调用super(不带参数或括号)使用相同的参数调用父方法:
在没有任何参数的情况下
super使用时,使用给予子类方法的参数.
为"参数变量"分配新值似乎改变了这种行为:
class MyClass
def foo(arg)
puts "MyClass#foo(#{arg.inspect})"
end
end
class MySubclass < MyClass
def foo(arg)
puts "MySubclass#foo(#{arg.inspect})"
super
arg = 'new value'
super
end
end
MySubclass.new.foo('inital value')
Run Code Online (Sandbox Code Playgroud)
输出:
MySubclass#foo("inital value")
MyClass#foo("inital value")
MyClass#foo("new value") # <- not the argument given to MySubclass#foo
Run Code Online (Sandbox Code Playgroud)
这是预期的吗?
这似乎是位置和关键字参数的预期行为,但它不适用于块参数:
class MyClass
def foo(&block)
puts "MyClass#foo { #{block.call.inspect} }"
end
end
class MySubclass < MyClass
def foo(&block)
puts "MySubclass#foo { #{block.call.inspect} }"
super …Run Code Online (Sandbox Code Playgroud) 我的代码是:
hash = { two: 2, three: 3 }
def hash_add(hash, new_key, new_value)
temp_hash = {}
temp_hash[new_key.to_sym] = new_value
temp_hash.merge!(hash)
hash = temp_hash
puts hash
end
hash_add(hash, 'one', 1)
Run Code Online (Sandbox Code Playgroud)
在方法中,puts hash返回{ :one => 1, :two => 2, :three => 3 },但是当hash1放入方法时,它在之后保持不变.这就像赋值不在函数之外.
我想我可以返回更新的哈希并在方法之外设置我想要更改的哈希:
hash = hash_add(hash, 'one', 1)
Run Code Online (Sandbox Code Playgroud)
但我只是不明白为什么我给哈希的赋值不会超出方法.
我有这个,有效:
def hash_add(hash, new_key, new_value)
temp_hash = {}
temp_hash[new_key.to_sym] = new_value
temp_hash.merge!(hash)
hash.clear
temp_hash.each do |key, value|
hash[key] = value
end
end
Run Code Online (Sandbox Code Playgroud)
这给了我调用这个方法时我想要的东西,但是像这样重建哈希似乎有点过分了.
我们将我们的应用程序从Rails 4.1.14升级到4.2.5.1,并遇到以下问题:
string = "SomeString"
ar_model = SomeArModel.new
ar_model.some_attribute = string
# next line is true for 4.1, but fails for 4.2
ar_model.some_attribute.object_id == string.object_id
Run Code Online (Sandbox Code Playgroud)
显然,对象设置器复制每个对象(如果我有一个数组,内部的每个对象也将被欺骗),我想知道,如果这是有意的并且是一些新的安全功能的一部分?
更新
我使用ruby-2.2.2p95作为两个rails版本.作为参考,我做了一个小项目:
rails new testproject
rails g model Building name:string
rails db:migrate
rails c
>> b = Building.new
>> name = "Testname"
>> b.name = name
>> name.object_id # => 70199493308960
>> b.name.object_id # => 70199493278780
Run Code Online (Sandbox Code Playgroud)
之后,我只在Gemfile中将Rails版本更改为4.1.14,并再次尝试=>两个object_ids都是相同的.所以它不能只依赖于Ruby版本......
UPDATE2
它也适用于ruby-2.2.3和JRuby 9.0.4.0 ...
ar_model.attributes_before_type_cast['some_attribute']包含真实对象.
我基本上是一个java开发人员.我在红宝石工作了大约一年.与java不同,Ruby是一种纯粹的面向对象的编程语言.这是一个疑问.它是按值传递还是按引用传递?Java作为pass-by-value工作:"当传递基元时,我看到该值被复制并传递给方法.但是如果有对象,则引用被复制并传递给方法.引用包含对象的位置在堆中.在方法调用期间,只传递对象的位置.因此不会创建重复的对象.同样的对象被修改."
但是当我尝试下面的ruby代码片段时,我得到了与Java相同的结果:"在方法调用期间,数字就像一个原语(比如在java中),而数组就像java中一样完美引用".现在,我很困惑.如果ruby中的所有内容都是对象,那么在方法调用期间为什么数字对象会重复?
class A
def meth1(a)
a = a+5
puts "a inside meth1---#{a}"
end
def meth2(array)
array.pop
puts "array inside meth2---#{array}"
end
end
obj1 = A.new
aa=5
obj1.meth1(aa)
puts "aa-----#{aa}"
arr = [3,4,5]
obj1.meth2(arr)
puts "arr---#{arr}"
Run Code Online (Sandbox Code Playgroud)
结果:
一个内部meth1 --- 10
AA ----- 5
数组里面的meth2 --- 34
ARR --- 34
我很难理解为什么这段代码有效:
def flatten(array, result = [])
array.each do |element|
if element.is_a? Array
flatten(element, result)
else
result << element
end
end
result
end
Run Code Online (Sandbox Code Playgroud)
特别是,为什么它可以在不必将 flatten 方法调用的结果分配给结果数组的情况下工作,如下所示:
def flatten1(array, result = [])
array.each do |element|
if element.is_a? Array
result = flatten(element, result)
else
result << element
end
end
result
end
Run Code Online (Sandbox Code Playgroud)
两者都产生相同的输出:
p flatten [1,2,[3,4,[5,[6]]]] # [1, 2, 3, 4, 5, 6]
p flatten1 [1,2,[3,4,[5,[6]]]] # [1, 2, 3, 4, 5, 6]
Run Code Online (Sandbox Code Playgroud) 好的,所以Ruby是'按值传递'.但是,如何在Ruby中精确定义"按引用传递"和"按值传递"?我用过这个答案传递参考值和传递值之间有什么区别?根据它,Ruby似乎是一个混合......
从技术上讲,Ruby似乎是"按值传递",区别在于当您将值传递给方法时该值不会获得COPIED.如果我们定义"value"=对象,并且"reference"=指向该对象的引用变量,那么"通过引用传递"是否有意义,如果它等同于"传递指向特定对象的引用变量"?然后,一旦传递了"引用",该方法就不会对对象进行COPY,而实际上具有可以直接操作的ORIGINAL对象本身(由变量引用).如我错了请纠正我.
编辑:我知道这个问题Ruby是通过引用还是通过值传递?但不同的人似乎对那里的参考/价值有不同的定义.
当我运行下面的ruby代码时,为什么我的数组被全局操作?我怎样才能在函数范围内操作数组?
a = [[1,0],[1,1]]
def hasRowsWithOnlyOnes(array)
array.map { |row|
return true if row.keep_if{|i| i != 1 } == []
}
false;
end
puts a.to_s
puts hasRowsWithOnlyOnes(a)
puts a.to_s
Run Code Online (Sandbox Code Playgroud)
$ ruby test.rb 输出:
[[1, 0], [1, 1]]
true
[[0], []]
Run Code Online (Sandbox Code Playgroud)
我无法让它发挥作用.我甚至试过.select{true}把它分配给一个新名字.范围如何在Ruby for Arrays中运行?仅供参考$ ruby -v:
ruby 2.2.1p85 (2015-02-26 revision 49769) [x86_64-linux]
Run Code Online (Sandbox Code Playgroud)