简体   繁体   English

全局变量还是局部变量?

[英]Global vs local variables?

I am wondering why my code works in one instance but doesn't in another. 我想知道为什么我的代码只能在一个实例中工作而不能在另一个实例中工作。 Does it have something to do with local and global variables? 它与局部和全局变量有关吗?

This works: 这有效:

def factorial num
  result = 1
  while (num > 1)
    result = result * num
    num -= 1
  end
  puts result
end

This doesn't work: 这不起作用:

result = 1

def factorial num
  while (num > 1)
    result = result.to_i * num
    num -= 1
  end
  puts result
end

Everything inside of a method definition cannot see local variables from other places. 方法定义中的所有内容都看不到其他地方的局部变量。 That sounds weird, but here's two ways to fix it: 听起来很奇怪,但是有两种解决方法:

    result = 1
    number = 10

    def factorial(num,result_value)
      while (num > 1)
        result_value = result_value.to_i * num
        num -= 1
      end
      puts result_value
    end

    factorial(number, result)

That passes result as an argument. 将结果作为参数传递。 That's a great way of handling the method because it doesn't allow you to change the value of result from within the method. 这是处理方法的好方法,因为它不允许您从方法内部更改结果的值。 That might not seem like a big deal but "pure methods" like this become very valuable as the size the code increases. 看起来似乎没什么大不了,但是随着代码的增加,像这样的“纯方法”变得非常有价值。

This is the "dirty" or un-pure way of doing the same thing: 这是做同一件事的“肮脏”或不纯净的方式:

@result = 1

def factorial(num)
  while (num > 1)
    @result = @result.to_i * num
    num -= 1
  end
  puts @result
end

Putting an @ in front of a variable name allows its scope to expand to methods defined outside of its scope. 在变量名前面放置一个@ ,可以将其范围扩展到其范围之外定义的方法。 This becomes a problem as the complexity of your code increases. 随着代码复杂度的增加,这成为一个问题。

Random personal opinion: even though Ruby doesn't require you to put the parentheses next to a method definition, you always should. 个人观点:尽管Ruby不需要您将括号放在方法定义的旁边,但您始终应该这样做。 It makes the code a lot more explicit and easier to read. 它使代码更加明确和易于阅读。 Follow your heart though ;) 虽然跟随你的心;)

You could experiment by prepending all result s with a $ sign, making it global. 您可以通过在所有result前加$符号进行实验,使其成为全局变量。 Prepending with a @ results in an instance variable, also interesting. 以@开头会产生一个实例变量,这也很有趣。 Sidenote: puts prints and returns nil , so your method returns nil . 旁注: puts打印并返回nil ,因此您的方法返回nil

result = 1 # line 1

def factorial num
  while (num > 1)
    result = result.to_i * num 
    num -= 1
  end
  puts result
end

In this code, factorial doesn't know about result variable from the line 1. 在这段代码中, factorial不知道第1行的result变量。
When Ruby find result = result.to_i * num in your method it will first assign nil to the result . 当Ruby在您的方法中找到result = result.to_i * num时,它将首先为result分配nil Then Ruby will try to run result.to_i * num . 然后,Ruby将尝试运行result.to_i * num Since result is already nil , result.to_i is equal 0. 由于result已经为nil ,所以result.to_i等于0。

Here is another example: 这是另一个示例:

def foo
  a = a
  puts "#{a.class}"
end
foo #NilClass

In the Doesn't Work version the result variable you've assigned to 1 isn't visible inside the factorial method. “不工作”版本中,您分配给1的result变量在factorial方法内不可见。

Now there is a possibly unexpected behaviour in Ruby that if you try to assign a variable and you refer to the same variable on the right hand side of the assignment, if that variable doesn't have a value yet then it is treated as nil rather than raising an error. 现在,在Ruby中可能发生了意外的行为,如果您尝试分配一个变量,并在赋值的右侧引用了相同的变量,则如果该变量没有值,则将其视为nil而不是而不是引发错误。 So the first time round the loop when you perform 所以当你第一次表演时

result = result.to_i * num

it's equivalent to result = nil.to_i * num and nil.to_i is equal to 0 so this then sets up result to be 0 for subsequent iterations of the loop and as you're just multiplying the value of result stays on 0. 它等效于result = nil.to_i * numnil.to_i等于0,因此在随后的循环迭代中将result设置为0,因为您乘以result的值保持为0。

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

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