如何使Ruby方法传递输出参数(更改引用参数的值)?

如何使Ruby方法传递输出参数(更改引用参数的值)?,ruby,methods,ruby-on-rails-3.2,pass-by-reference,argument-passing,Ruby,Methods,Ruby On Rails 3.2,Pass By Reference,Argument Passing,我试图在ruby中创建一个带有输出参数的方法 我读了不同的帖子,讨论了ruby是通过值传递参数,还是通过引用传递参数 我明白在严格意义上,Ruby总是按值传递,但传递的值实际上是一个引用。关于这一点有这么多争论的原因 我发现有几种方法可以更改引用变量的值。 例如,当它是一个数组、哈希或字符串或合并时,使用replace方法当它是散列时 我发现使用integer,我可以在方法之外更改和传递值,而无需使用任何特殊方法 我的问题是关于其他对象的。 例如,我想检索对象的“id”属性和对象引用本身:

我试图在ruby中创建一个带有输出参数的方法

我读了不同的帖子,讨论了ruby是通过值传递参数,还是通过引用传递参数

我明白在严格意义上,Ruby总是按值传递,但传递的值实际上是一个引用。关于这一点有这么多争论的原因

我发现有几种方法可以更改引用变量的值。 例如,当它是一个数组、哈希或字符串或合并时,使用replace方法当它是散列时

我发现使用integer,我可以在方法之外更改和传递值,而无需使用任何特殊方法

我的问题是关于其他对象的。 例如,我想检索对象的“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
class RestaurantControllerpizza\u name)。第一个
#无名披萨
如果pizza.nil返回false?
#第一位顾客订购了这个比萨饼
订单的id\u=订单。其中(:pizza\u id=>pizza.id)。首先
真的
结束
结束
我的比萨饼名='margerita'
我的订单号=零
我的比萨饼=零
my_restaurant=餐厅管理员。新建
如果我的餐厅要送比萨饼(我的比萨饼名称、我的订单号、我的比萨饼)
放入“比萨饼配送:{my_order_id}”
雷克斯狗。吃(我的比萨饼)
结束

如何使其工作?(order_id和my_pizza保留为nil)

Ruby只有pass-by值,就像Python和Java一样。与Python和Java一样,对象也不是直接的值,而是通过引用操作的

您似乎已经了解了它的工作原理——分配给局部变量对调用方作用域没有任何影响。为了与调用方作用域“共享”信息而不是返回,您必须在对象上使用某种方法来“改变”传递的引用所指向的对象(如果存在这种方法;即,如果对象是可变的)。但是,这只是修改相同的对象,而不是提供对新对象的引用,这是您想要的

如果不愿意返回值,可以传递一个可变容器(如一个元素的数组),然后被调用函数可以对其进行变异,并将任何内容放入其中,并在调用方作用域中看到它


另一种选择是让函数执行一个块。该函数将为块提供新的值
pizza
,然后块(由调用方提供)可以决定如何处理它。调用者可以传递一个只在其自身范围内设置pizza的块。

在大多数情况下,out参数是没有多值返回的语言的一种变通方法。在Ruby中,我只返回一个包含函数所有输出值的数组。或者将可变值作为对象中的实例变量,并将函数作为该对象上的方法。

谢谢这两个答案

看起来我终于找到了一个等价的解决方案:可变容器

我创建了一个新类“
OutputParameter
”,其中包含(作为attr\u访问器)我希望从方法输出的参数。然后我将这个类的一个实例传递给我的方法

  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
类输出参数
属性访问器:订单id,比萨饼
结束
类RestaurantController<应用程序控制器
def PIZA_to_deliver(PIZA_名称、输出_参数)
#比萨饼
比萨饼=比萨饼。其中(:name=>pizza\u name)。第一个
#无名披萨
如果pizza.nil返回false?
#第一位顾客订购了这个比萨饼
订单的id\u=订单。其中(:pizza\u id=>pizza.id)。首先
#返回的输出值
输出_parameters.pizza=pizza
output\u parameters.order\u id=订单的id\u
真的
结束
结束
我的比萨饼名='margerita'
my_output=OutputParameters.new
my_restaurant=餐厅管理员。新建
如果我的餐厅。披萨要送(我的披萨名称,我的输出)那么
放入“要交付的比萨饼:{my_output.order_id}”
雷克斯狗。吃(我的输出。比萨饼)
结束

您建议的哈希或数组似乎更好,因为它更具适应性:我不必声明类

我只会使用合并!方法

  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
class RestaurantControllerpizza\u name)。第一个
#无名披萨
如果pizza.nil返回false?
#第一位顾客订购了这个比萨饼
订单的id\u=订单。其中(:pizza\u id=>pizza.id)。首先
#返回的输出值
输出\u hash.merge!({:pizza=>pizza})
输出\u hash.merge!({:id\u of theu order=>id\u of theu order})
真的
结束
结束
我的比萨饼名='margerita'
my_output_hash={}
my_restaurant=餐厅管理员。新建
如果我的餐厅。比萨饼要送(我的比萨饼名,我的比萨饼输出)
放置“要交付的比萨饼:{my_output_hash[:id_of the_order]}”
rex_dog.eat(我的\u输出\u散列[:比萨饼])
结束

您可以使用多个返回值,如下所示:

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)
与人们使用时的操作非常相似:

f, err := os.Open("filename.ext")
if err != nil {
    log.Fatal(err)
}
// do something with the open *File f