Как работает метод [квадратная скобка] в Ruby?

Translate

Я прохожу черезПрограммирование на Ruby - прагматичное руководство программистаи наткнулись на этот фрагмент кода:

class SongList
  def [](key)
    if key.kind_of?(Integer)
      return @songs[key]
    else
      for i in [email protected]
        return @songs[i] if key == @songs[i].name
      end
    end
    return nil
  end
end

Я не понимаю, как работает метод определения []?

Почему ключ находится вне [], но когда вызывается метод, он находится внутри []?

Может ли ключ быть без скобок?

Я понимаю, что есть гораздо лучшие способы написать это, и знаю, как написать свой собственный метод, который работает, но этот [] метод меня просто сбивает с толку ... Любая помощь приветствуется, спасибо

This question and all comments follow the "Attribution Required."

Все ответы

Translate

Методы в ruby, в отличие от многих языков, могут содержать некоторые специальные символы. Один из них - синтаксис поиска в массиве.

Если бы вы реализовали свой собственный хеш-класс, в котором при извлечении элемента из хеш-кода вы хотели бы его отменить, вы могли бы сделать следующее:

class SillyHash < Hash

  def [](key)
    super.reverse
  end

end

Вы можете доказать это, вызвав хеш со следующим:

a = {:foo => "bar"}
 => {:foo=>"bar"} 
a.[](:foo)
 => "bar" 
a.send(:[], :foo)
 => "bar" 

Итак, def [] определил метод, который используется, когда вы делаетеmy_array["key"]Другие методы, которые могут показаться вам странными:

class SillyHash < Hash

  def [](key)
    super.reverse
  end

  def []=(key, value)
    #do something
  end

  def some_value=(value)
    #do something
  end

  def is_valid?(value)
    #some boolean expression
  end

end

Чтобы уточнить, определение[]не имеет отношения к массивам или хешам. Возьмем следующий (надуманный) пример:

class B
  def []
    "foo"
  end
end

 B.new[]
 => "foo" 
Источник
Translate

Это просто синтаксический сахар. Существуют определенные шаблоны синтаксиса, которые переводятся в отправленные сообщения. В частности

a + b

такой же как

a.+(b)

и то же самое относится к==, !=, <, >, <=, >=, <=>, ===, &, |, *, /, -, %, **, >>, <<, !==, =~и!~также.

Также,

!a

такой же как

a.!

и то же самое относится к~.

Потом,

+a

такой же как

[email protected]

и то же самое относится к-.

Плюс,

a.(b)

такой же как

a.call(b)

Также существует специальный синтаксис для сеттеров:

a.foo = b

такой же как

a.foo=(b)

И последнее, но не менее важное: есть специальный синтаксис для индексации:

a[b]

такой же как

a.[](b)

и

a[b] = c

такой же как

a.[]=(b, c)
Источник
Translate

квадратные скобки - это имя метода, напримерArray#sizeу вас естьArray#[]как метод, и вы даже можете использовать его как любой другой метод:

array = [ 'a', 'b', 'c']
array.[](0) #=> 'a'
array.[] 1  #=> 'b'
array[2]    #=> 'c'

последний является чем-то вроде синтаксического сахара и делает то же самое, что и первый. ВArray#+работают аналогично:

array1 = [ 'a', 'b' ]
array2 = [ 'c', 'd' ]
array1.+(array2) #=> [ 'a', 'b', 'c', 'd' ]
array1.+ array2  #=> [ 'a', 'b', 'c', 'd' ]
array1 + array2  #=> [ 'a', 'b', 'c', 'd' ]

Вы даже можете складывать такие числа:

1.+(1) #=> 2
1.+ 1  #=> 2
1 + 1  #=> 2

то же самое работает с/, *, -и многое другое.

Источник
Translate

Это перегрузчик операторов, он переопределяет или дополняет поведение метода внутри определенного вами класса или класса, поведение которого вы изменяете. Вы можете сделать это с другими операторами, отличными от []. В этом случае вы изменяете поведение [], когда он вызывается в любых экземплярах класса SongList.

Если у вас есть songlist = SongList.new, а затем вы выполняете songlist ["foobar"], тогда ваш собственный def вступит в действие и будет предполагать, что "foobar" должен быть передан как параметр (ключ), и он будет работать с "foobar "все, что говорит метод, должно выполняться с ключом.

Пытаться

class Overruler
    def [] (input)
          if input.instance_of?(String)
            puts "string"
          else
            puts "not string"
          end
     end
end
foo = Overruler.new
foo["bar"].inspect
foo[1].inspect
Источник
Leave a Reply
You must be logged in to post a answer.
Об авторе