ruby 中的元/动态/泛型编程

发布于 2024-10-25 08:15:46 字数 402 浏览 1 评论 0原文

我正在尝试创建一个通用方法:

class Foo
  attr_reader

  def add(object)
    item = @item.find { |item| item.(#the method is calling object.class) == object if item.is_a?(object.class)}
  end
end

我想创建一个通用方法,它根据参数类来比较数组的元素。

示例:

item.method1 == method1 if item.is_a?(method1.class) 

其中 method1 是类的名称。

另外,我需要一个关于元编程和动态/通用编程的完整教程。

I am trying to make a generic method:

class Foo
  attr_reader

  def add(object)
    item = @item.find { |item| item.(#the method is calling object.class) == object if item.is_a?(object.class)}
  end
end

I want to create a generic method which compares the element of an array depending the parameter class.

Example:

item.method1 == method1 if item.is_a?(method1.class) 

where method1 is the name of class.

Also, I need a complete tutorial about metaprogramming and dynamic/generic programming.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

千鲤 2024-11-01 08:15:46

我不确定你想从你的例子中做什么。作为一般规则,在 Ruby 中,您不检查类型。它是动态类型的有一个原因:您可以编写适用于任何碰巧支持您的代码对其调用的方法的对象的代码。

从我从您的评论中可以看出,您想要扩展类 Array 因此,当您在像 an_array.pack 这样的数组上调用方法时,会搜索该数组Pack 的实例并返回。 Ruby 有一个每当发现方法不存在时就会调用的方法,称为 Module#method_missing。例如,如果我随机决定调用 4.to_dragon(magic: 4, height: 700),Ruby 解释器将尝试查找 to_dragon 作为定义在Fixnum(数字类型)继承链中的某些类或模块。如果您没有对该链执行任何奇怪的操作,我们会使用以下参数调用对象 4 上的 method_missing[:to_dragon, { magic: 4 ,高度:700}]。基本上,这是附加到参数前面的名称,并且应该给出一个块。

使用此技术,您可以重写 method_missing 来获取此代码作为解决方案:

class String
  def method_to_class
    split('_').map(&:capitalize).join
  end
end

class Array
  def method_missing(method_name, *arguments, &block)
    find do |element|
      element.class.name == method_name.to_s.method_to_class
    end || super
  end
end

将方法添加到 String 中,以将方法名称转换为类名称。然后,您在 Array 上重新定义 method_missing 以检查每个元素以查看类名是否与给定的类名匹配。如果找到,则将其返回。否则(我们使用 Ruby 奇特的 || 运算符来执行此操作),从该函数返回的值为 nil ,第二个操作数为 ||被返回。这恰好是 method_missing 的默认实现(我们通过 super 关键字获得)并返回调用应有的错误。

唯一的潜在问题是,如果您的元素的类名与数组上已定义的方法名相同,那么将调用这些元素而不是这种特殊技术。例如,调用 an_array.hash 将为您提供数组的哈希代码,而不是哈希的第一个实例。

在这方面更安全的技术与我认为您尝试做的更相似。它实际上使用类对象,您可以使用它来重写其他方法:

class Array
  def add(class_object)
    class << self
      define_method class_object.name do
        find do |element|
          element.is_a? class_object
        end
      end
    end
  end
end

这直接在数组实例上定义新方法。例如:

an_array = [Array, Hash, Dragon].map &:new
an_array.add Hash
an_array.hash    #=> {}

如果这个答案不包含解决方案,它至少应该引导您更接近!

I am unsure of what you are trying to do from your example. As a general rule, in Ruby, you don't check for types. It is dynamically typed for a reason: you can write code that works for any objects that happen to support the methods your code calls on them.

From what I can tell from your comments, you want to extend the class Array so, when you call a method on an array like an_array.pack, the array is searched for an instance of Pack and returned. Ruby has a method called whenever a method is found not to exist called Module#method_missing. For example, if I randomly decide to call 4.to_dragon(magic: 4, height: 700), the Ruby interpreter will attempt to find to_dragon as a public method defined on some class or module in the Fixnum (type of numbers) inheritance chain. Provided you have not done something strange to that chain, we get a call to method_missing on the object 4 with these arguments: [:to_dragon, { magic: 4, height: 700 }]. Basically, that's the name appended to the front of the arguments, and a block should one be given.

Using this technique, you can override method_missing to get this code as a solution:

class String
  def method_to_class
    split('_').map(&:capitalize).join
  end
end

class Array
  def method_missing(method_name, *arguments, &block)
    find do |element|
      element.class.name == method_name.to_s.method_to_class
    end || super
  end
end

You add a method to String to convert a method name to a class name. Then, you redefine method_missing on Array to check each element to see if the class name matches the given class name. If one is found, then that is returned. Otherwise (and we do this using Ruby's fancy || operator), the value returned from that function is nil and the second operand to || is returned. This happens to be the default implementation for method_missing (which we get by the super keyword) and returns the error the call deserves.

The only potential issue with that is, if you have elements that have class names identical to method names that are already defined on arrays, then those will be called instead rather than this special technique. For example, calling an_array.hash will give you the hash code of the array rather than the first instance of a hash.

A safer technique in this respect is more similar to what I think you were trying to do. It actually uses class objects, and you can use it to override other methods:

class Array
  def add(class_object)
    class << self
      define_method class_object.name do
        find do |element|
          element.is_a? class_object
        end
      end
    end
  end
end

This defines new methods directly on an instance of an array. For example:

an_array = [Array, Hash, Dragon].map &:new
an_array.add Hash
an_array.hash    #=> {}

If this answer does not include a solution, it should at least guide you closer!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文