简体   繁体   English

Ruby:参数与变量

[英]Ruby: Parameter vs variables

So I started learning ruby and I found out that we can have default values in a method, this looked similar to just having instance variables, Is there any importance or benefit this gives apart from reducing the lines of code? 因此,我开始学习ruby,发现可以在方法中使用默认值,这看起来与仅具有实例变量相似。除了减少代码行数之外,这是否有其他重要性或好处?

//This //这个

def order_food(price, size="large", quantity = 8)
    if quantity == 1
      extra = "salad"
    else
      extra = "Burgers"
    end
    puts "#{quantity} #{size} #{extra}, coming right up!"
  end

//To this //到此

def order_food(price)
    size = "large"
    quantity = 8
    if quantity == 1
      extra = "salad"
    else
      extra = "Burgers"
    end
    puts "#{quantity} #{size} #{extra}, coming right up!"
  end

While thinking deep into this I realized one of the very great benefit this provides is flexibility and readability. 在深思熟虑的同时,我意识到它提供的巨大好处之一就是灵活性和可读性。 So for instance, I could pass in parameters like 例如,我可以传入类似

order_food(2, "small", 90)

This allows me to override the default values which is better than having to change a variables content while 这使我可以覆盖默认值,这比必须在更改变量内容的同时

order_food(9, "extraLarge")

gets the default quantity that I have set 获取我设置的默认数量

It's not the same as an instance variable. 它与实例变量不同。 An instance variable has scope for an instance of a class and is declared using the @ symbol. 实例变量具有类实例的作用域,并使用@符号声明。

For example: 例如:

class MyClass

  def initialise
    @my_instance_variable = 'hello world'
  end

  def method_one
    puts "I have access to the instance variable and it is #{@my_instance_variable}"
  end
end

What you have shown are both declarations of local variables for the scope of the method only, however one is defining a parameter to your method and the other isn't. 您所显示的都是用于方法范围的局部变量声明,但是一个正在为您的方法定义参数,而另一个则没有。

def order_food(price, size="large", quantity = 8)

is not the equivalent of: 等于:

def order_food(price)
    size = "large"
    quantity = 8

Although size and quantity are both variables and both have scope only for the order_food method, the first is declaring them as parameters the method can accept, so it can be called like so: 尽管大小和数量都是变量,并且都只适用于order_food方法,但首先是将它们声明为该方法可以接受的参数,因此可以这样称呼:

order_food(5, 'small', 2)

Whereas in the second example these cannot be set by the callee - they are fixed at 'large' and 8. 而在第二个示例中,被调用者无法设置这些值-它们固定为“大”和8。

It is not necessary to declare method parameters with defaults but by doing so the callee doesn't need to provide them and the default values would be used instead. 不必使用默认值声明方法参数,但这样一来,被调用方就无需提供它们,而将使用默认值。 So for the method declaration of: 因此,对于以下方法的声明:

def order_food(price, size="large", quantity = 8)

you could make the following calls: 您可以拨打以下电话:

order_food price: 10, quantity: 2 #will use default size with value 'large'
order_food price: 5, size: 'small' #will use default quantity of 8

First of all, the variables are local variables not instance variables. 首先,变量是局部变量,而不是实例变量。 Instance variables belong to the instance of a class and are notated with the @var_name notation, while local variables belong to a scope (very simplistically that is anything surrounded by a do ... end . More detail here ) and are notated with just the variable name ( my_var = "some_value" ). 实例变量属于类的实例,并用@var_name表示法表示,而局部变量属于作用域(非常简单,这是用do ... end包围的任何东西。 在这里有更多详细信息 ),并仅用变量名( my_var = "some_value" )。

It depends on what you are using the method for. 这取决于您使用该方法的目的。 If you want to be able to pass the arguments quantity and size than you should use the first one. 如果您希望能够传递参数quantitysize ,则应该使用第一个参数。 The second one will give you and ArgumentError if you try to pass more than 1 argument. 如果您尝试传递多个ArgumentError ,第二个ArgumentError将给您和ArgumentError The first one will set the values of quantity = 8 and size = "large" if they are not passed, but if they are passed, it will use the passed values. 如果没有通过,第一个将设置quantity = 8size = "large"的值,但是如果通过,它将使用通过的值。

If you want to be able to call the method and set the size and quantity as arguments and if they are not passed use size = "large" and quantity = 8 as defaults, use the first method: 如果您希望能够调用该方法并将大小和数量设置为参数,并且如果不传递它们,则将size = "large"并把quantity = 8作为默认值,请使用第一种方法:

order_food "9.00" #=> "8 large burgers, coming right up!"
order_food "9.00", "small", 1 #=> "1 small salad, coming right up!"

The second method will not allow you to pass either of the other two arguments, and they will always be set so quantity = 8 and size = "large" . 第二种方法不允许您传递其他两个参数中的任何一个,并且始终将它们设置为quantity = 8size = "large" This has it's benefits, because sometimes you don't want the variables to be change-able with arguments. 这有其好处,因为有时您不希望变量可以通过参数更改。 So with the second method: 因此,使用第二种方法:

order_food "9.00" #=> "8 large burgers, coming right up!"
order_food "9.00", "small", 1 #=> ArgumentError: wrong number of arguments (given 3, expected 1)

Here's a re-reworked version of your code that's more Ruby-like: 这是代码的重新设计版本,更像Ruby:

def order_food(price, size: :large, quantity: 1)
  extras =
    case (quantity)
    when 1
      "salad"
    else
      "Burgers"
    end

  "#{quantity} #{size} #{extra}, coming right up!"
end

puts order_food(2, :small, 8)

Doing display ( puts ) inside a method is often giving the method too much responsibility. 在方法内部进行显示( puts )通常会使方法承担太多责任。 Split out display concerns from the compositional ones. 将显示关注点与组成关注点分开。 Maybe you want to write that to a file, or embed it in HTML. 也许您想将其写入文件或嵌入HTML中。 puts inside the method limits your options. puts方法限制了您的选择。

Also take advantage of keyword arguments if you want to have a number of them that are somewhat arbitrary in nature. 如果您想拥有许多本质上是任意的关键字参数,也可以利用关键字参数。 This allows you to skip one and use the other without having code that has to re-specify defaults. 这样一来,您无需使用必须重新指定默认值的代码就可以跳过一个而使用另一个。

There are in fact 4 common ways to pass parameters to a function. 实际上,有四种将参数传递给函数的常用方法。 Your first example is the most common one but you made a bad example I'm afraid. 您的第一个例子是最常见的例子,但恐怕您做了一个不好的例子。 Your quantity is always 8, so the if is superfluous, also the parametere price isn't used so also superfluous This would be the same as the following 您的数量始终为8,因此,如果是多余的,那么也不会使用参数价格,因此也是如此。这将与以下相同

    def order_food price
      "8 large Burgers, coming right up!"
    end

But that is not your purpose I presume. 但这不是我想的目的。

So, it would be something like this First method 因此,这将类似于First方法

def order_food1(size, quantity, price)
  extra = quantity == 1 ? :salad : :Burgers
  cost  = quantity * price
  "#{quantity} #{size} #{extra}, coming right up! Thats is #{cost} dollar please"
end

+ fast (see benchmarks) +快速(请参阅基准)

+ everybody uses it and understands it in one glace +每个人都一目了然地使用它并理解它

- you have to know the parameters and the order in which they are defined, you need to read the API for less common uses methods -您必须知道参数及其定义的顺序,您需要阅读API以了解较不常用的方法

- you must provide all the parameters -您必须提供所有参数

Next : using optional parameters with default values 下一页 :使用具有默认值的可选参数

def order_food2(size = "large", quantity = 1, price = 4)
  extra = quantity == 1 ? :salad : :Burgers
  cost  = quantity * price
  "#{quantity} #{size} #{extra}, coming right up! Thats is #{cost} dollar please"
end

+ also widely used +也被广泛使用

+ no need to use parameters if they are the default ones +如果它们是默认参数,则无需使用参数

- you still need to know the order and meaning of the parameters and if the last is used you need them all -您仍然需要知道参数的顺序和含义,如果使用了最后一个,则全部需要它们

Next : using a hash as parameter 下一页 :使用哈希作为参数

def order_food3(opts = {})
  opts = {size: :large, quantity: 1, price: 4}.merge!(opts)
  extra = opts[:quantity] == 1 ? :salad : :Burgers
  cost  = opts[:quantity] * opts[:price]
  "#{opts[:quantity]} #{opts[:size]} #{extra}, coming right up! Thats is #{cost} dollar please"
end

- less used, your method self is a little harder to read -使用较少,您的方法自我很难读

- slower - 慢点

+ no need to know parameters you don't need, nor the order +无需知道不需要的参数或顺序

+ the use of the method is more readable +使用该方法更具可读性

Next : a simplified version of the previous method 下一页 :先前方法的简化版本

def order_food4(size: :large, quantity: 1, price: 4)
  extra = :quantity == 1 ? :salad : :Burgers
  cost  = quantity * price
  "#{quantity} #{size} #{extra}, coming right up! Thats is #{cost} dollar please"
end

- slower - 慢点

+ method itself and use of it are more readable +方法本身及其用法更具可读性

Which one is better ? 哪一个更好 ? Depends on personal taste and the situation. 取决于个人品味和情况。 I use all of them and there is nothing in the design guides as far as I know that prefares one or the other. 我都使用了它们,据我所知,设计指南中没有任何内容。 In practice you will even combine some of them. 实际上,您甚至可以结合其中的一些。 Parameters that are seldom changed are best given a default value and vice versa. 最好将很少更改的参数设置为默认值,反之亦然。 Methods that are called many times (eg recursive ones) could benefit from the faster and less memory consuming method 1. In my opinion, readability is most important for a Ruby script, so if having a lot of parameters and feasable use method 3 or 4. 多次调用的方法(例如递归方法)可能会受益于速度更快且内存消耗较少的方法1。在我看来,可读性对于Ruby脚本最为重要,因此,如果有很多参数并且可行的使用方法3或4 。

Some examples of use and benchmarks.. 使用和基准的一些示例。

puts order_food1("large", 3, 4)
puts order_food2("large", 3, 4)
puts order_food3(size: "large", quantity: 3, price: 4)
puts order_food3
puts order_food4(size: "large", quantity: 3, price: 4)
puts order_food4

# 3 large Burgers, coming right up! Thats is 12 dollar please
# 3 large Burgers, coming right up! Thats is 12 dollar please
# 3 large Burgers, coming right up! Thats is 12 dollar please
# 1 large salad, coming right up! Thats is 4 dollar please
# 3 large Burgers, coming right up! Thats is 12 dollar please
# 1 large Burgers, coming right up! Thats is 4 dollar please

require 'benchmark'

Benchmark.bmbm do |x|
  x.report("order_food1    ")   { 10000.times { order_food1("large", 3, 12) }}
  x.report("order_food2    ")   { 10000.times { order_food2("large", 3, 12) }} # all parameters given
  x.report("order_food2_def")   { 10000.times { order_food2 }} # using default parameters
  x.report("order_food3    ")   { 10000.times { order_food3(size: "large", quantity: 3, price: 12) }} # all parameters given
  x.report("order_food3 def")   { 10000.times { order_food3 }} # using default parameters
  x.report("order_food4    ")   { 10000.times { order_food3(size: "large", quantity: 3, price: 12) }} # all parameters given
  x.report("order_food4 def")   { 10000.times { order_food3 }} # using default parameters
end

#                       user     system      total        real
# order_food1       0.015000   0.000000   0.015000 (  0.010420)
# order_food2       0.000000   0.000000   0.000000 (  0.010675)
# order_food2_def   0.016000   0.000000   0.016000 (  0.011007)
# order_food3       0.015000   0.000000   0.015000 (  0.020182)
# order_food3 def   0.016000   0.000000   0.016000 (  0.016954)
# order_food4       0.015000   0.000000   0.015000 (  0.020256)
# order_food4 def   0.000000   0.000000   0.000000 (  0.016968)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM