我正在尝试在ruby中创建一个带输出参数的方法。
我阅读了不同的帖子here和here关于对rubher ruby的讨论通过其参数by-value或by-reference和
我强调,严格来说,Ruby总是按值传递,但传递的值实际上是一个引用。之所以存在这么多争论的原因。
我发现有几种方法可以改变引用变量的值。 例如,当它是一个数组,一个哈希或一个字符串时使用替换方法,或者当它是哈希时合并!。
我发现使用整数,我可以更改并在我的方法之外传递值,而无需使用任何特殊方法。
我的问题是关于其他对象。 例如,我想检索一个对象的'id'属性,以及对象引用本身:
class RestaurantController < ApplicationController
def pizza_to_deliver(pizza_name, id_of_the_order, pizza)
# pizza to eat
pizza = Pizza.where(:name => pizza_name).first
# unknown pizza
return false if pizza.nil?
# first customer order about this pizza
id_of_the_order = Orders.where(:pizza_id => pizza.id).first
true
end
end
my_pizza_name = 'margerita'
My_order_id = nil
my_pizza = nil
my_restaurant = RestaurantController.new
if my_restauant.pizza_to_deliver(my_pizza_name, My_order_id, my_pizza) then
puts "Pizza to deliver : #{my_order_id}"
rex_dog.eat(my_pizza)
end
如何使这个工作? (order_id和my_pizza保持为零)
答案 0 :(得分:2)
Ruby只传递值,就像Python和Java一样。与Python和Java一样,对象不是直接的值,而是通过引用来操作。
看起来你已经明白它是如何工作的 - 分配一个局部变量永远不会对调用者范围产生任何影响。并且除了返回之外,要与调用者范围“共享”信息,必须在对象上使用某种方法来“改变”对象(如果存在这样的方法;即,如果对象是可变的),则传递的引用指向该方法。但是,这只是修改相同的对象,而不是提供您想要的新对象的引用。
如果您不愿意返回该值,则可以传递一个可变容器(如一个元素的数组),然后被调用的函数可以变异并将任何内容放在那里并让它在调用者范围内看到。 / p>
另一个选择是让函数占用一个块。该函数将为块提供pizza
的新值,然后块(由调用者给出)可以决定如何处理它。调用者可以传递一个块,只需将披萨设置在自己的范围内。
答案 1 :(得分:1)
在大多数情况下,out参数是没有多值返回的语言的变通方法。在Ruby中,我只返回一个包含该函数的所有输出值的Array。或者在对象中创建可变值实例变量,并在该对象上创建一个方法。
答案 2 :(得分:0)
感谢您的回答。
我似乎最终得到了一个等效的解决方案:可变容器。
我创建了一个新类“OutputParameter
”,其中包含(作为 attr_accessors )我想从我的方法输出的参数。然后我将这个类的实例传递给我的方法。
class OutputParameters
attr_accessor :order_id, pizza
end
class RestaurantController < ApplicationController
def pizza_to_deliver(pizza_name, output_parameters)
# pizza to eat
pizza = Pizza.where(:name => pizza_name).first
# unknown pizza
return false if pizza.nil?
# first customer order about this pizza
id_of_the_order = Orders.where(:pizza_id => pizza.id).first
# Output values returned
output_parameters.pizza = pizza
output_parameters.order_id = id_of_the_order
true
end
end
my_pizza_name = 'margerita'
my_output = OutputParameters.new
my_restaurant = RestaurantController.new
if my_restaurant.pizza_to_deliver(my_pizza_name, my_output) then
puts "Pizza to deliver : #{my_output.order_id}"
rex_dog.eat(my_output.pizza)
end
你建议的哈希或数组似乎更好主意,因为它更具适应性:我不必声明一个类。
我会使用合并!方法
class RestaurantController < ApplicationController
def pizza_to_deliver(pizza_name, output_hash)
# pizza to eat
pizza = Pizza.where(:name => pizza_name).first
# unknown pizza
return false if pizza.nil?
# first customer order about this pizza
id_of_the_order = Orders.where(:pizza_id => pizza.id).first
# Output values returned
output_hash.merge!({:pizza => pizza})
output_hash.merge!({:id_of_the_order => id_of_the_order})
true
end
end
my_pizza_name = 'margerita'
my_output_hash = {}
my_restaurant = RestaurantController.new
if my_restaurant.pizza_to_deliver(my_pizza_name, my_output_hash) then
puts "Pizza to deliver : #{my_output_hash[:id_of_the_order]}"
rex_dog.eat(my_output_hash[:pizza])
end
答案 3 :(得分:0)
您可以使用多个返回值,如下所示:
def maybe_get_something
...
return nil, "sorry" if bad_condition
...
something, nil
end
...
something, err = maybe_get_something
if !err.nil?
handle(err)
return
end
do_something_with(something)
与人们使用Go时的行为非常相似:
f, err := os.Open("filename.ext")
if err != nil {
log.Fatal(err)
}
// do something with the open *File f