How does defining [square bracket] method in Ruby work?

后端 未结 4 576
不思量自难忘°
不思量自难忘° 2020-12-12 21:52

I am going through Programming Ruby - a pragmatic programmers guide and have stumbled on this piece of code:

class SongList
  def [](key)
    if key.kind_of?         


        
相关标签:
4条回答
  • 2020-12-12 22:44

    Methods in ruby, unlike many languages can contain some special characters. One of which is the array lookup syntax.

    If you were to implement your own hash class where when retrieving an item in your hash, you wanted to reverse it, you could do the following:

    class SillyHash < Hash
    
      def [](key)
        super.reverse
      end
    
    end
    

    You can prove this by calling a hash with the following:

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

    So the def [] defined the method that is used when you do my_array["key"] Other methods that may look strange to you are:

    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
    

    Just to clarify, the definition of a [] method is unrelated to arrays or hashes. Take the following (contrived) example:

    class B
      def []
        "foo"
      end
    end
    
     B.new[]
     => "foo" 
    
    0 讨论(0)
  • 2020-12-12 22:47

    It's an operator overloader, it overrides or supplements the behavior of a method inside a class you have defined, or a class the behavior of which you are modifying. You can do it to other operators different from []. In this case you are modifying the behavior of [] when it is called on any instances of class SongList.

    If you have songlist = SongList.new and then you do songlist["foobar"] then your custom def will come into operation and will assume that "foobar" is to be passed as the parameter (key) and it will do to "foobar" whatever the method says should be done to key.

    Try

    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
    
    0 讨论(0)
  • 2020-12-12 22:48

    It's just syntactic sugar. There are certain syntax patterns that get translated into message sends. In particular

    a + b
    

    is the same as

    a.+(b)
    

    and the same applies to ==, !=, <, >, <=, >=, <=>, ===, &, |, *, /, -, %, **, >>, <<, !==, =~ and !~ as well.

    Also,

    !a
    

    is the same as

    a.!
    

    and the same applies to ~.

    Then,

    +a
    

    is the same as

    a.+@
    

    and the same applies to -.

    Plus,

    a.(b)
    

    is the same as

    a.call(b)
    

    There is also special syntax for setters:

    a.foo = b
    

    is the same as

    a.foo=(b)
    

    And last but not least, there is special syntax for indexing:

    a[b]
    

    is the same as

    a.[](b)
    

    and

    a[b] = c
    

    is the same as

    a.[]=(b, c)
    
    0 讨论(0)
  • 2020-12-12 22:49

    the square brackets are the method name like Array#size you have Array#[] as a method and you can even use it like any other method:

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

    the last one is something like syntactic sugar and does exactly the same as the first one. The Array#+ work similar:

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

    You can even add numbers like this:

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

    the same works with /, *, - and many more.

    0 讨论(0)
提交回复
热议问题