Можно ли вызвать функцию модуля из класса, который также находится в этом модуле - PullRequest
5 голосов
/ 01 июля 2010

В этом коде Ruby:

Module M
  Class C < Struct.new(:param)
    def work
      M::helper(param)
    end
  end

  def helper(param)
    puts "hello #{param}"
  end
end

При попытке запустить

я получаю сообщение об ошибке "неопределенный метод" помощник "для ошибки" M: Module "
c = M::C.new("world")
c.work

, но вызов M::helper("world") напрямую из другого класса работает нормально. Могут ли классы не вызывать функции модуля, которые определены в том же модуле, в котором они определены? Есть ли способ обойти это, кроме перемещения класса за пределы модуля?

Ответы [ 4 ]

4 голосов
/ 01 июля 2010

Чтобы вызвать M::helper, вам нужно определить его как def self.helper; end. Для сравнения взгляните на helper и helper2 в следующем измененном фрагменте

module M
  class C < Struct.new(:param)
    include M     # include module to get helper2 mixed in
    def work
      M::helper(param)
      helper2(param)
    end
  end

  def self.helper(param)
    puts "hello #{param}"
  end

  def helper2(param)
    puts "Mixed in hello #{param}"
  end
end

c = M::C.new("world")
c.work
4 голосов
/ 01 июля 2010

перед модулем нужно добавить self:

module M
  class C < Struct.new(:param)
    def work
      M::helper(param)
    end
  end

  def self.helper(param)
    puts "hello #{param}"
  end
end
2 голосов
/ 01 июля 2010

C пытается вызвать helper на M, когда helper не входит в синглтон-класс M.Кроме того, вы продолжаете говорить, что helper является функцией модуля, когда это только метод.Если сделать helper модульной функцией, код будет работать:

module M
  class C < Struct.new(:param)
    def work
      M::helper(param)
    end
  end

  module_function

  def helper(param)
    puts "hello #{param}"
  end
end

Включение модуля в класс также будет работать:

module M
  class C < Struct.new(:param)
    include M

    def work
      helper(param)
    end
  end

  def helper(param)
    puts "hello #{param}"
  end
end

В первом примере helper - этоположить в класс синглтона M с module_function.Второй пример импортирует методы M в C, чтобы C мог их использовать.Другое отличие состоит в том, что во-первых, вы сможете звонить M.helper из любой точки вашего кода.Во втором вы сможете вызывать helper из любого экземпляра C в вашем коде.Чтобы это исправить, сделайте helper private:

module M
  class C < Struct.new(:param)
    include M

    def work
      helper(param)
    end
  end

  private
  def helper(param)
    puts "hello #{param}"
  end
end
1 голос
/ 11 февраля 2016

Вот несколько объяснений:

Из ruby ​​docs .

Модуль - это набор методов и констант.Методы в модуле могут быть методами экземпляра или методами модуля.Методы экземпляра отображаются как методы в классе, когда модуль включен, а методы модуля - нет. И наоборот, методы модуля могут вызываться без создания инкапсулирующего объекта, а методы экземпляра - нет.(См. Module # module_function.)

self.methodname внутри модуля создает метод модуля.

В этом случае, когда вы вызываете M::helper, вы фактически делаете M.helper когда вы смотрите на это с точки зрения разработчика C ++.В данном случае получателем является объект Module (экземпляр модуля встроенного типа ruby).


Другой способ взглянуть на это - понять концепцию получателя, каждый вызов метода состоит из получателя и имени метода(+ опционально params и кодовый блок).Получатель может быть Module object, Class object или экземпляром определенного пользователем класса.

Вы можете вызывать методы Module (или Class) только для объекта Module (или Class).Вы можете вызывать любой метод (Module / Class / instance) в экземпляре.

Если вы хотите вызвать метод экземпляра, определенный в модуле, вы должны передать ему приемник с помощью including этого модуля в некотором классе.и создание его экземпляра.

Так что в этом случае другое решение может быть:

module MM
  def helper(param)
    puts "hello #{param}"
  end

  class ReceiverClass
    include MM           # add helper() to ReceiverClass
  end

  class C < Struct.new(:param)
    def work
      ReceiverClass.new.helper(param)
    end
  end
end

c = MM::C.new("world")
c.work
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...