【问题标题】:Ruby: How ist the .+ method working internally?Ruby:.+ 方法在内部是如何工作的?
【发布时间】:2021-12-03 10:57:03
【问题描述】:

假设我创建了一个对象 a 并给它一个方法 .to_i,为什么不能将这个对象添加到 Integer 中?

>> a = Object.new
=> #<Object:0x0000000006cfa9d0>
?> def a.to_int
?>   42
>> end
=> :to_int
>> 3 + a
(irb):5:in `+': Object can't be coerced into Integer (TypeError)
        from (irb):5:in `<main>'

感谢 Stefan,它成功了!

irb(main):010:1* def a.coerce other
irb(main):011:1*   [other, 42]
irb(main):012:0> end
=> :coerce
irb(main):013:0> 1 + a
=> 43

【问题讨论】:

标签: ruby type-conversion integer


【解决方案1】:

你还需要调用to_int方法,否则解释器怎么知道你想做什么?

>> 3 + a.to_int

Ruby 不进行自动转换。

>> 3 + "5" 

这将给出同样的错误,即使 "5" 有一个非常好的 to_i 方法。顺便提一句。 ruby 中的 to int 方法通常称为to_i,以防您想保持一致性。

【讨论】:

  • 是的,to_i 是对的
  • to_intto_i 具有非常精确定义的含义,并且在正确使用 to_int 和正确使用 to_i 时定义了用例。说“ruby 中的 int 方法通常称为 to_i,以防你想保持一致性”是非常具有误导性的,因为它与一致性无关,而与哪种方法是正确的方法有关。
【解决方案2】:

给对象加整数可以通过实现+来实现,例如:

class Foo
  def initialize(value)
    @value = value
  end

  def to_i
    @value
  end

  def +(other)
    Foo.new(to_i + other.to_i)
  end
end

Foo.new(5) + 4
#=> #<Foo:0x00007fbd22050640 @value=9>

为了将Foo 的实例添加到整数,您还必须实现coerce,它将左侧的值作为参数并返回一个数组,其中两个值都转换为Foo 实例,例如:

class Foo
  # ...

  def coerce(other)
    [Foo.new(other.to_i), self]
  end
end

这给了你:

4 + Foo.new(5)
#=> #<Foo:0x00007fba600e3e28 @value=9>

Numeric 的文档包含另一个示例。

如果参数不是整数,coerce 在内部由Integer#+ 调用:(C 代码)

VALUE
rb_int_plus(VALUE x, VALUE y)
{
    if (FIXNUM_P(x)) {
        return fix_plus(x, y);
    }
    else if (RB_TYPE_P(x, T_BIGNUM)) {
        return rb_big_plus(x, y);
    }
    return rb_num_coerce_bin(x, y, '+');
}

rb_num_coerce_bin 调用coerce,然后在返回值上调用二元运算符+

在 Ruby 中,这将是:(简化)

class Integer
  def +(other)
    if other.is_a?(Integer)
      # ...
    else
      x, y = other.coerce(self)
      x + y
    end
  end
end

【讨论】:

  • 完美!强制是关键词。再次感谢您!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-20
  • 1970-01-01
  • 2011-01-31
  • 2012-04-18
  • 2022-12-07
  • 1970-01-01
相关资源
最近更新 更多