Помогите объяснить символы как хеш-значения в Ruby? - PullRequest
2 голосов
/ 31 августа 2011

Всего Руби Нуб.Я прохожу LRTHW Зеда Шоу, и я застрял в упражнении Hash.Я не вижу смысла в этом коде и не могу найти в Интернете ничего похожего на него.

cities = {'CA' => 'San Francisco', 'MI' => 'Detroit', 'FL' => 'Jacksonville'}

cities['NY'] = 'New York'
cities['OR'] = 'Portland'

def find_city (map, state)
  if map.include? state
    return map[state]
  else
    return "Not found."
  end
end

cities[:find] = method(:find_city)

while true
  print "State? (Enter to quit) "
  state = gets.chomp

  break if state.empty?

  puts cities[:find].call(cities, state)
end

По сути, я просто застрял.Я не могу установить связь между тем, как я набираю текст в государстве, и оно возвращает город.Любое глупое объяснение будет с благодарностью.

Ответы [ 3 ]

2 голосов
/ 31 августа 2011

Здесь есть хеш (города) с ключом 3 пары => значение

cities = {'CA' => 'San Francisco', 'MI' => 'Detroit', 'FL' => 'Jacksonville'}

Вы можете получить доступ к этим значениям с помощью клавиши:

puts cities['CA']  #=>  'San Francisco'

Теперь добавим две новые пары.

cities['NY'] = 'New York'
cities['OR'] = 'Portland'

Весь хеш будет:

p cities #=> {'CA' => 'San Francisco', 'MI' => 'Detroit', 'FL' => 'Jacksonville', 'NY' => 'New York', 'OR' => 'Portland'}

Теперь определен метод с именем find_city. Требуется хеш и ключ.

def find_city (map, state)
  # if hash has the key, return its value. (There are better ways to do it.)
  if map.include? state
    return map[state]
  else
    return "Not found."
  end
end

Здесь есть худший кусок кода на Ruby, который я когда-либо видел.

cities[:find] = method(:find_city)

Хорошо, этот код получает метод find_city и превращает его в Method объект, который может быть присвоен переменной. НО, вместо использования обычной локальной переменной, она сохраняется в значении хеша cities!

Этот объект похож на метод, но это объект вместо метода, и его нужно вызывать с помощью call (в Ruby 1.8.7).

Я буду использовать переменную с именем my_meth (это может быть любое имя), чтобы объяснить лучше.

# get the method find_city and turns it into an object assigned to my_meth
my_meth = method(:find_city)

while true
  print "State? (Enter to quit) "
  state = gets.chomp

  break if state.empty?

  # here we use find_city on the cities hash.
  puts my_meth.call(cities, state)
end

puts my_meth.class

Но вместо того, чтобы использовать переменную, оригинальный код хранил объект Method в хэше cities. Итак, города будут:

cities[:find] = method(:find_city)
p cities #=> {'CA' => 'San Francisco', 'MI' => 'Detroit', 'FL' => 'Jacksonville', 'NY' => 'New York', 'OR' => 'Portland', :find => (the Method object)}

Таким образом, вы можете получить доступ к find_city через cities[:find].call.

2 голосов
/ 31 августа 2011

Символ представляет себя так же, как 0 представляет 0 - и символ только равен самому себе.(Учтите, что :foo == "foo" ложно, поэтому hash[:foo] никогда не может ссылаться на пару hash["foo"], даже если оба могут вычислять один и тот же объект).

Так что cities[:find] просто мало что даетсмысл и это путает данные (хэш-карты, связанные с большим городом) с операцией над данными ... это может быть cityFindFunction вместо этого.Однако, поскольку использование самого метода вполне допустимо (здесь нет необходимости преобразовывать его в функцию!), Рассмотрите это упрощение:

cities = {'CA' => 'San Francisco', 'MI' => 'Detroit', 'FL' => 'Jacksonville'}

def find_city (map, state)
  if map.include? state
    # if this hash contains the state, e.g. "CA" then
    # return a big city in the state
    return map[state]
  else
    # otherwise return a diagnostic message
    return "Not found."
  end
end

while true
  print "State? (Enter to quit) "
  state = gets.chomp

  break if state.empty?

  # this is a method invocation, no need for "call"!
  puts find_city(cities, state)
end

Это можно еще больше упростить, возвращая nil вместо «Не найдено»."(пусть вызывающая сторона справится с этим) или используя значение по умолчанию хэша.В любом случае, я надеюсь, что вышеприведенное показывает «суть» того, что делается.

Удачное кодирование.


Краткий рассказ о методе и методе против функции.

В Ruby методы являются , а не значениями первого класса.Скорее, это «сообщения», на которые данный объект реагирует.Вызов метода find_city(cities, state) выше удобен для self.__send__(:find_city, cities, state).(Ну, не совсем, потому что __send__ сам по себе является вызовом метода, но это суть того, что происходит внутри ...; -)

Функции (типа Proc ) и объекты типа Method , с другой стороны, являются просто объектами.Таким образом, в отличие от методов , они являются «первоклассными значениями».Чтобы вызвать / применить a Объект функции / метода , используйте метод call ( Функция / Метод ), который выполняетфункция с заданными параметрами и возвращает Функции / Методы возвращаемое значение.

Метод method возвращает метод объект - , связанный с экземпляром объекта method, был вызван - для данного метода .

Надежда, которая несколько объясняет остальное; -)

1 голос
/ 31 августа 2011

Это не так сложно.

  • Первые 4 строки заполняют ваш хэш аббревиатурой => название состояния
  • Затем вы определяете метод find_city, который получает карту и аббревиатуруи печатает соответствующее имя.
  • После этого вы помещаете метод с именем find_city в хэш-города с ключом: find.
  • city [: find] .call (города, штат) простовызывает ранее сохраненный метод с аргументами.

Вместо использования здесь символов, вы могли бы использовать строки или целые числа, по крайней мере, для хеш-части.Более того, вы могли бы использовать метод ("find_city") вместо метода (: find_city)

Вы просто должны понимать базовую рубиновую логику и ссылаться на методы как на объекты.

...