【问题标题】:Namespace collision with top-level methods与顶级方法的命名空间冲突
【发布时间】:2016-01-14 13:40:37
【问题描述】:

我有以下 Ruby 命名空间问题:

我在“库”中有许多顶级方法,其中我有一个 get_name(param) 方法。 问题是我想在一个拥有自己的 get_name() 方法(没有参数!)的类中使用这个 get_name(param) 方法。 当然这会导致问题,因为这两种方法不同,并且类中的新方法会覆盖顶级方法。

有没有办法做这样的事情:

def get_name(param)
  puts param
end

class Foo 
  def get_name()
    puts "name"
  end
  def bar()
    self.get_name() #should work and print name, i.e. it uses the get_name method of Foo
    get_name("abc") #should work and print abc, i.e. it uses the top-level method
  end
end

我想知道是否有一种简单的方法可以实现这一点,而无需更改顶级方法的名称或范围。 (目标是让那些无需修改即可作为全局方法使用,但仍然能够调用 Foo 的实例方法而不会出错。

【问题讨论】:

  • 我的建议:只需在顶层创建一个别名。别名不会修改它们的原像 ;-)
  • 这没有意义。顶级get_name 方法是一个实例方法,但您正试图在Foo 实例上调用它。

标签: ruby


【解决方案1】:

如果库方法真的是顶级方法并且不属于任何类或模块,那么它们将被定义为Object 类的private 方法。

您可以执行以下操作来调用它:

  def bar()
    self.get_name()
    Object.send(:get_name, "abc")  # Will print "abc" to console
  end

【讨论】:

    【解决方案2】:

    所谓的“顶级方法”只是main对象的一个​​方法,也就是一个Object。如果您希望该方法能够(几乎)在任何地方被调用,您应该将其设为内核方法

    module Kernel
      def get_name(param)
        puts param
      end
    end
    

    请注意,Kernel 几乎位于任何类祖先链的尾部(BasicObject 之前),这意味着几乎所有对象都是Kernel。所以在你的Foo 类中,你可以像这样覆盖它:

    class Foo
      def get_name(*args)
        return super if args.any?
        puts 'name'
      end
    end
    

    编辑

    如果您不能将这些顶级方法设为内核方法,则可以将main 对象存储在常量或全局变量中,然后在其上调用这些顶级方法。

    $main = self
    
    class Foo
      def get_name(*args)
        return $main.send(:get_name, *args) if args.any?
        puts 'name' 
      end
    end
    

    【讨论】:

      【解决方案3】:

      首先:没有所谓的“顶级方法”。 Ruby 中只有一种方法:实例方法。

      您指的方法是Objectprivate 实例方法。由于Object 是几乎任何其他类的超类(不包括Object 及其超类),如果您确定继承层次结构中的其他地方没有其他同名方法,您可以使用Method#super_method 来访问该方法,然后调用它:

      def get_name(param)
        puts param
      end
      
      class Foo 
        def get_name
          puts 'name'
        end
      
        def bar
          get_name #should work and print name, i.e. it uses the get_name method of Foo
          method(:get_name).super_method.('abc') #should work and print abc, i.e. it uses the top-level method
        end
      end
      
      Foo.new.bar
      # name
      # abc
      

      或者,如果您知道在继承层次结构中是否有任何同名的其他方法,您可以获取对UnboundMethod的引用直接来自Object 然后bindcall 它:

      class Foo 
        def bar
          get_name #should work and print name, i.e. it uses the get_name method of Foo
          Object.instance_method(:get_name).bind(self).('abc') #should work and print abc, i.e. it uses the top-level method
        end
      end
      
      Foo.new.bar
      # name
      # abc
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-20
        • 2011-12-30
        • 1970-01-01
        • 1970-01-01
        • 2012-09-10
        相关资源
        最近更新 更多