【问题标题】:Ruby error - Undefined MethodRuby 错误 - 未定义的方法
【发布时间】:2017-02-22 17:39:41
【问题描述】:

我正在尝试编写一个函数,该函数将在数组中找到与传递给函数的字符串匹配的项。请参阅下面的代码。

class Island 
  def filter(string) 
    for element in self
      if element.include? (string)
        yield(element)
      end
    end
  end 
end
list =    ["sasha","rory","rob","anthony","andre","tariq","kimberly","antoinette"]
list.filter("an"){|i| puts i}</i>

我如何不断收到“未定义的方法‘文件管理器’#

我不确定我做错了什么。

【问题讨论】:

  • 您在Island 上定义方法,但在数组上调用它。那是怎么回事?

标签: ruby-on-rails ruby windows web


【解决方案1】:

首先让我反对@Sravan 发布的解决方案:

虽然猴子修补类是正确的——有时甚至是一个很好的解决方案——但你必须小心如何去做,因为它可能会成为定时炸弹:

Ruby 不断发展,新版本通常会向现有类添加方法。这意味着如果你添加一个方法 Array#search,并且新版本的 Ruby 也会添加一个同名的方法,你的新方法将静默地覆盖 Ruby 中的方法。您可能很长时间都不会注意到它,直到您使用应该使用 Rubys Array#search 的功能 - 也许通过使用 stdlib 中的新功能 - 并且您会得到奇怪的结果。追查此类错误可能是一场噩梦。当您使用 search 作为方法名称时,情况正是如此。

现在,那该怎么做呢?三种可能:

(1) 如果您进行猴子补丁,请至少使用一个不太可能成为官方接口一部分的方法名称。它可能有你的项目名称作为前缀,或者大量的下划线字符,等等。请注意,这不是 100% 万无一失的:Ruby 的更高版本可能会在后台添加一个与您选择的名称完全相同的私有方法,但当然,您的名称越奇怪,发生这种情况的可能性就越小。

(2) 如果您不喜欢这种使用“笨拙”名称的想法,您至少可以在定义新方法之前测试它是否已经存在,如果不存在则抛出异常:

class Array
  if self.method_defined?(:search)
    raise "#{self.class}::search already defined"
  else
    def search(...)
     ...
    end
  end
end

(3) 第三种可能性是避免猴子修补并将该方法保留在您的 Island 类中。在这种情况下,方法定义会有所不同:

class Island
  def self.filter(array, string)
    ...
  end
end

它会被调用

Island.filter(myarray, mystring)

更新:忘记了第四种可能性:

(4) 你可以让 Island 成为 Array 的子类。我不知道您还想对您的岛屿做什么,但也许这是一个值得考虑的选择:

class Island < Array
  def filter(string)
    ...
  end
end

当然,在调用filter的时候,你需要把你的数组变成一个孤岛,然后才能使用它:

list = Island.new([....])

【讨论】:

  • 这肯定是最好的解决方案。尝试使用 Array 初始化 Island 类,而不是覆盖 Array 本身。
  • 这很好地解释了如何实现我的课程。我选择使用第 4 个。非常感谢。
【解决方案2】:

按照 ruby​​ 的convention over configuration,您可以在任何类中添加/覆盖任何方法

因此,向数组类添加一个函数可以让所有数组都可以访问它。所以,在这个解决方案中。

1) 首先是你在Island class中使用了filter函数,相反,你需要在Array class中使用strong> 因为列表是一个数组。

    class Array 
      def filter(string) 
        for element in self
          if element.include? (string)
            yield(element)
          end
        end
      end 
    end

    list =    ["sasha","rory","rob","anthony","andre","tariq","kimberly","antoinette"]

   list.filter("an"){|i| puts i}

    O/P:
    anthony
    andre
    antoinette

2) 由于 Filter 是其他答案所建议的 keyword,因此请为其取另一个名称。例如:search

class Array 
     def search(string) 
        for element in self
          if element.include? (string)
            yield(element)
          end
        end
     end 
end

list.search("an"){|i| puts i}

【讨论】:

  • 很高兴为您提供帮助。你可以接受我的回答。如果它对你有帮助。 :)
  • “因为过滤器是关键字”——不,不是。即使它一个关键字,那也不是问题。您可以将方法命名为与关键字相同的名称。核心库中甚至还有这样的方法:Object#classRange#beginRange#endMatchData#beginMatchData#endFiber::yieldProc#yieldEnumerator::Yielder#yieldEnumerator#next、@98765433 Integer#next, Symbol#next.
  • @Jorg,谢谢。是的,我知道我可以覆盖一个方法,但是如果他需要同时使用他的方法和过滤方法怎么办?
  • 我不明白你的意思。您说filter 是关键字,因此您需要更改名称。这两种说法都是错误的:首先,filter 不是 关键字。其次,将方法命名为与关键字相同是完全可以的。第三,OP 已经说过他们正在使用您的第一个选项,即带有 filter 的选项,并且可以接受。
  • 我同意,使用filter 这个词甚至可以。我只是说Array 类已经有一个名为 filter 的方法。我只是告诉他,如果您使用除此之外的任何名称会更好。尝试另一个。就是这样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多