2

我正在尝试使用 ruby​​ 中的输出参数创建一个方法。

我在这里这里阅读了关于红宝石是否按值或按引用传递其参数的讨论的不同帖子和

我理解严格来说,Ruby 总是按值传递,但传递的值实际上是一个引用。为什么会有这么多争论的原因。

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

我发现使用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

如何使这个工作?(order_id 和 my_pizza 保持为零)

4

4 回答 4

3

Ruby 只能通过值传递,就像 Python 和 Java 一样。与 Python 和 Java 一样,对象不是直接的值,而是通过引用进行操作的。

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

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

另一种选择是让函数占用一个块。该函数将为块提供 的新值pizza,然后块(由调用者给出)可以决定如何处理它。调用者可以传递一个简单地将比萨饼设置在自己范围内的块。

于 2013-02-19T22:08:49.630 回答
3

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

于 2013-02-20T03:06:07.120 回答
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
于 2013-02-21T14:08:16.867 回答
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
于 2018-03-25T07:06:59.613 回答