4

私は が初めてでRuby、 との比較を実装しようとしていますGradesが、例に示されていました

include Comparable

class Grade
        attr_accessor :grades, :grade

        def initialize( grade = "" )
                self.grades = { :nil => -1, :"F" => 0, :"D-" => 1, :"D" => 2, :"D+" => 3,
                                :"C-" => 4, :"C" => 5, :"C+" => 6, :"B-" => 7, :"B" => 8,
                                :"B+" => 9, :"A-" => 10, "A+" => 11 }
                if self.grades[ grade ]
                        self.grade = grade
                else
                        self.grade = nil

                end
        end

        def <=>( other )
                if self.grades[ self.grade ] < self.grades[ other.grade ]
                        return -1
                elsif self.grades[ self.grade ] == self.grades[ other.grade ]
                        return 0
                else
                        return 1
                end
        end
end

a_plus = Grade.new("A+")
a      = Grade.new("A")
[a_plus, a].sort # should return [a, a_plus]

だから、私は得ています:

grade.rb:31:in `<': comparison of Fixnum with nil failed (ArgumentError)
    from grade.rb:31:in `<=>'
    from grade.rb:43:in `sort'
    from grade.rb:43:in `<main>'

ComparisonRubyでオブジェクト間を実装したいだけ

4

3 に答える 3

8

Ruby Doc モジュール Comparableから:

Comparable は <=> を使用して、従来の比較演算子 (<、<=、==、>=、および >) と between? メソッドを実装します。

そういうものを実装したい場合は、実装するだけ<=>です。残りは自動的に続きます。たとえば、を定義する<と、クラスが台無しになります。

次のようなことができます。

class Grade
  include Comparable
  attr_reader :index
  @@grades = %w[F D- D D+ C- C C+ B- B B+ A- A+]
  def initialize (grade = nil); @index = @@grades.index(grade).to_i end
  def <=> (other); @index <=> other.index end
end

a_plus = Grade.new("A+")
a      = Grade.new("A")
a_plus > a
# => true
[a_plus, a].sort
# => `[a, a_plus]` will be given in this order
于 2012-12-20T13:57:17.473 に答える
2

次のようにするだけです。

class Foo
  include Comparable
  attr_reader :bar
  def initialize bar
    @bar = bar
  end

  def <=>(another_foo)
    self.bar <=> another_foo.bar
  end
end

したがって、<=>の定義で、独自のロジックを追加できます。

于 2012-12-20T14:02:41.237 に答える
0

元の投稿にコメントする : 次のようなメッセージがある場合

「>」内: nil:NilClass (NoMethodError) の未定義のメソッド「>」

値を表示するには、printステートメントを配置するだけです。したがって、パラメータ in は文字列ですが、ハッシュ内のキーはシンボルであるため、 in が nil を返していることがすぐにわかります。したがってinitialize、で変換する必要があります。self.grades[ self.grade ]Grade.new("A+")to_sym

元のクラスを print ステートメントで再配置 (および >(other) のみを表示):

class Grade
    attr_reader :grade
    @@grades = { :nil  => -1, :"F"  =>  0, :"D-" =>  1, :"D"  => 2, :"D+" => 3,
                 :"C-" =>  4, :"C"  =>  5, :"C+" =>  6, :"B-" => 7, :"B"  => 8,
                 :"B+" =>  9, :"A-" => 10, :"A+" => 11 }

    def initialize( p_grade = "" )
        @grade = p_grade if @@grades[ p_grade.to_sym ]
        puts "init param=#{p_grade} value=<#{@@grades[ p_grade.to_sym ]}> @grades=<#{@grade}>"
    end

    def >( other )
        puts "in >( other ) : key1=#{self.grade} key2=#{other.grade}"
        puts "in >( other ) : $#{@@grades[ self.grade ]}$ ??? $#{@@grades[ other.grade ]}$"
        return @@grades[ self.grade ] > @@grades[ other.grade ]
    end
end

print '--- Grade.new("A+") : '; a_plus = Grade.new("A+")
print '--- Grade.new("A")  : '; a      = Grade.new("A")
print '--- a_plus > a : '; p a_plus > a 

実行:

$ ruby -w t.rb
--- Grade.new("A+") : init param=A+ value=<11> @grades=<A+>
--- Grade.new("A")  : t.rb:9: warning: instance variable @grade not initialized
init param=A value=<> @grades=<>
--- a_plus > a : in >( other ) : key1=A+ key2=
in >( other ) : $$ ??? $$
t.rb:15:in `>': undefined method `>' for nil:NilClass (NoMethodError)
    from t.rb:21:in `<main>'

Grade.new("A"): Aはハッシュに存在しないため、インスタンス変数 @grade は設定されずself.grades[ self.grade ] > ...、メッセージ>を nil (定義されていない NilClass のインスタンス) に送信します>

トリック @grades=<#{xyz}> に注意してください。補間された値を <> または $$ で囲むと、値が nil の場合に表示がより明確になります。
ruby -w t.rb の -w にも注意してください。興味深い警告メッセージが表示されます。

于 2012-12-20T18:20:23.297 に答える