Ruby 为不同类型的对象设置成员资格
Ruby Set membership for objects of different types
Ruby 不是一种类型化的语言,因此我觉得这很奇怪。示例:
class Test
attr_reader :field
def initialize(f)
@field = String(f)
end
def ==(other)
field == String(other)
end
def eql?(other)
field.eql? String(other)
end
def hash
field.hash
end
def to_s
field
end
end
s = Set.new([Test.new('string')])
# => [#<Test:0x007fc97da17ea0 @field="string">]
puts Test.new('string').eql?(Test.new('string'))
# true
puts Test.new('string').hash == Test.new('string').hash
# true
puts s.member? Test.new('string')
# true
puts s.member? Test.new('other')
# false
puts Test.new('string') == 'string'
# true
puts Test.new('string').eql? 'string'
# true
puts Test.new('string').hash == 'string'.hash
# true
但是,
puts s.member? 'string'
# false
似乎 Ruby 在内部强制执行某些类型检查。应该是这样吗?
你的主要问题是String#eql?
:
puts Test.new('string').eql? 'string'
# true
puts 'string'.eql? Test.new('string')
# false
你说得对,似乎有一些内部类型检查:
rb_str_eql(VALUE str1, VALUE str2)
{
if (str1 == str2) return Qtrue;
if (!RB_TYPE_P(str2, T_STRING)) return Qfalse;
return str_eql(str1, str2);
}
请注意,您的示例在反过来使用时有效:
s = Set.new(['string'])
puts s.member? Test.new('string')
# true
如果你真的想实现这种行为,你可以使用 monkey-patch String#eql?
:
module TestStringEquality
def eql?(other)
other.is_a?(Test) ? other.eql?(self) : super
end
end
s = Set.new([Test.new('string')])
puts s.member? 'string'
# false
class String
prepend TestStringEquality
end
puts s.member? 'string'
# true
小心,每个gem.
大概都会用到这个方法
最后,请记住Set
is a pure Ruby implementation with Hash
作为后端。它可能使 google 获取信息和文档变得更容易。
Ruby 不是一种类型化的语言,因此我觉得这很奇怪。示例:
class Test
attr_reader :field
def initialize(f)
@field = String(f)
end
def ==(other)
field == String(other)
end
def eql?(other)
field.eql? String(other)
end
def hash
field.hash
end
def to_s
field
end
end
s = Set.new([Test.new('string')])
# => [#<Test:0x007fc97da17ea0 @field="string">]
puts Test.new('string').eql?(Test.new('string'))
# true
puts Test.new('string').hash == Test.new('string').hash
# true
puts s.member? Test.new('string')
# true
puts s.member? Test.new('other')
# false
puts Test.new('string') == 'string'
# true
puts Test.new('string').eql? 'string'
# true
puts Test.new('string').hash == 'string'.hash
# true
但是,
puts s.member? 'string'
# false
似乎 Ruby 在内部强制执行某些类型检查。应该是这样吗?
你的主要问题是String#eql?
:
puts Test.new('string').eql? 'string'
# true
puts 'string'.eql? Test.new('string')
# false
你说得对,似乎有一些内部类型检查:
rb_str_eql(VALUE str1, VALUE str2)
{
if (str1 == str2) return Qtrue;
if (!RB_TYPE_P(str2, T_STRING)) return Qfalse;
return str_eql(str1, str2);
}
请注意,您的示例在反过来使用时有效:
s = Set.new(['string'])
puts s.member? Test.new('string')
# true
如果你真的想实现这种行为,你可以使用 monkey-patch String#eql?
:
module TestStringEquality
def eql?(other)
other.is_a?(Test) ? other.eql?(self) : super
end
end
s = Set.new([Test.new('string')])
puts s.member? 'string'
# false
class String
prepend TestStringEquality
end
puts s.member? 'string'
# true
小心,每个gem.
大概都会用到这个方法最后,请记住Set
is a pure Ruby implementation with Hash
作为后端。它可能使 google 获取信息和文档变得更容易。