Undefined local variable for hash in method ruby

岁酱吖の 提交于 2019-11-27 08:56:39

问题


for some reason I'm getting

NameError: undefined local variable or method `states' for main:Object

though states is clearly defined. What is going on here?

In irb I added states in and accessed it fine using states[:CA] but when I put it in a method I got that error.

states = {
  CA: 'California',
  FL: 'Florida',
  MI: 'Michigan',
  NY: 'New York',
  OR: 'Oregon',
}

states[:CO] = 'Colorado'
states[:HI] = 'Hawaii'

cities = {
  CA: ['Alameda', 'Apple Valley', 'Exeter'],
  FL: ['Exeter', 'Amelia Island', 'Bunnell'],
  MI: ['Ann Arbor', 'East China', 'Elberta'],
  NY: ['Angelica', 'Apalachin', 'Canadice'],
  OR: ['Amity', 'Boring', 'Camas Valley'],
  CO: ['Blanca', 'Crestone', 'Dillon', 'Fairplay'],
  HI: ['Kailua', 'Hoopili', 'Honolulu'],
}

def describe_state state
  puts state
  description = "#{state.to_s} is for #{states[state]}."
  description << " It has #{citites[state].length} major cities:"
  cities[state].each do |x| ' ' << description end
end

puts describe_state :CA

回答1:


states is a local variable (because it starts with a lowercase letter). Local variables are local to the scope they are defined in (that's why they are called local variables, after all). So, states is defined in the scope of the script, but not in the scope of the method describe_state.

Method scopes don't nest, the only scopes that do nest are block scopes, so you would need to use a block. Thankfully, there is a method called define_method which creates a method from a block:

states = {
  CA: 'California',
  FL: 'Florida',
  MI: 'Michigan',
  NY: 'New York',
  OR: 'Oregon',
}

states[:CO] = 'Colorado'
states[:HI] = 'Hawaii'

cities = {
  CA: ['Alameda', 'Apple Valley', 'Exeter'],
  FL: ['Exeter', 'Amelia Island', 'Bunnell'],
  MI: ['Ann Arbor', 'East China', 'Elberta'],
  NY: ['Angelica', 'Apalachin', 'Canadice'],
  OR: ['Amity', 'Boring', 'Camas Valley'],
  CO: ['Blanca', 'Crestone', 'Dillon', 'Fairplay'],
  HI: ['Kailua', 'Hoopili', 'Honolulu'],
}

define_method(:describe_state) do |state|
  "#{state} is for #{states[state]}. " \
  "It has #{cities[state].length} major cities: #{cities[state].join(', ')}"
end

puts describe_state :CA
#=> CA is for California. It has 3 major cities: Alameda, Apple Valley, Exeter



回答2:


The method can't access the outside variables. You could use instance variables instead. From the documentation:

Instance variables are shared across all methods for the same object.

Example:

@states = {
  CA: 'California',
  FL: 'Florida',
  MI: 'Michigan',
  NY: 'New York',
  OR: 'Oregon',
}

@states[:CO] = 'Colorado'
@states[:HI] = 'Hawaii'

@cities = {
  CA: ['Alameda', 'Apple Valley', 'Exeter'],
  FL: ['Exeter', 'Amelia Island', 'Bunnell'],
  MI: ['Ann Arbor', 'East China', 'Elberta'],
  NY: ['Angelica', 'Apalachin', 'Canadice'],
  OR: ['Amity', 'Boring', 'Camas Valley'],
  CO: ['Blanca', 'Crestone', 'Dillon', 'Fairplay'],
  HI: ['Kailua', 'Hoopili', 'Honolulu'],
}

def describe_state state
  description = "#{state.to_s} is for #{@states[state]}."
  description << " It has #{@cities[state].length} major cities: "
  description << @cities[state].join(', ')
end

puts describe_state :CA
#=> CA is for California. It has 3 major cities: Alameda, Apple Valley, Exeter

(I've fixed a minor bug in describe_state)




回答3:


states and cities are not defined in the function pass them in like

def describe_state state, states, cities
 ..
end
puts describe_state :CA, states, cities

will work



来源:https://stackoverflow.com/questions/24030193/undefined-local-variable-for-hash-in-method-ruby

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!