简体   繁体   中英

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. 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. Prepending with a @ results in an instance variable, also interesting. Sidenote: puts prints and returns nil , so your method returns 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.
When Ruby find result = result.to_i * num in your method it will first assign nil to the result . Then Ruby will try to run result.to_i * num . Since result is already nil , result.to_i is equal 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.

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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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