Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 为什么`Kernel::String`check`to_str`会产生结果,而`Kernel::Integer`不会';不检查“to_int”结果?_Ruby - Fatal编程技术网

Ruby 为什么`Kernel::String`check`to_str`会产生结果,而`Kernel::Integer`不会';不检查“to_int”结果?

Ruby 为什么`Kernel::String`check`to_str`会产生结果,而`Kernel::Integer`不会';不检查“to_int”结果?,ruby,Ruby,Kernel::Integer和Kernel::String首先尝试调用“long”方法(分别调用int和分别调用str)和“short”方法(分别调用i和分别调用str)来转换参数。这两种方法都会检查“short”方法结果的类别,并在需要时引发错误: [1] pry(main)> class Dummy [1] pry(main)* def to_i [1] pry(main)* "42" [1] pry(main)* end [1] pry(main)* def t

Kernel::Integer
Kernel::String
首先尝试调用“long”方法(
分别调用int
分别调用str
)和“short”方法(
分别调用i
分别调用str
)来转换参数。这两种方法都会检查“short”方法结果的类别,并在需要时引发错误:

[1] pry(main)> class Dummy
[1] pry(main)*   def to_i
[1] pry(main)*     "42"
[1] pry(main)*   end
[1] pry(main)*   def to_s
[1] pry(main)*     42
[1] pry(main)*   end
[1] pry(main)* end;
[2] pry(main)> Integer(Dummy.new)
TypeError: can't convert Dummy to Integer (Dummy#to_i gives String)
from (pry):9:in `Integer'
[3] pry(main)> String(Dummy.new)
TypeError: can't convert Dummy to String (Dummy#to_s gives Fixnum)
这种行为似乎是合乎逻辑的,因为“short”方法应该只是给出一个“表示”。另一方面,“long”方法应该只在所讨论的对象本质上是整数或字符串()时才实现

但是,一旦我们实现了“long”方法,行为就会变得不一致:

[4] pry(main)> class Dummy
[4] pry(main)*   def to_int
[4] pry(main)*     "42"
[4] pry(main)*   end
[4] pry(main)*   def to_str
[4] pry(main)*     42
[4] pry(main)*   end
[4] pry(main)* end;
[5] pry(main)> Integer(Dummy.new)
=> "42"
[6] pry(main)> String(Dummy.new)
TypeError: can't convert Dummy to String (Dummy#to_str gives Fixnum)
为什么对结果的处理不同

我正在使用ruby 2.1.2,顺便说一句:

[7] pry(main)> RUBY_VERSION
=> "2.1.2"

下面是调用
Kernel#Integer
,也称为
rb#fu Integer
时发生的情况:

  • rb\u f\u integer
    调用
    rb\u convert\u to\u integer
  • rb\u convert\u to\u integer
    调用
    convert\u类型(val,“integer”,“to\u int”,FALSE)
  • convert_type
    返回
    val.to_int
    ,无论它是否为整数
  • rb\u convert\u to\u integer
    的重要部分是:

    tmp = convert_type(val, "Integer", "to_int", FALSE);
    if (NIL_P(tmp)) { // checks if val.to_int is nil. this is the line that causes this
        return rb_to_integer(val, "to_i");
    }
    return tmp;
    
  • 因此,它检查
    to_int
    的返回值是否为零,而不是它是否为整数。我在代码中注释的那一行就是导致这个bug的那一行。在上面对
    rb\u to\u integer
    的调用中检查
    to\u i
    的结果类型(如果
    to\u int
    的结果为nil或
    to\u int
    未定义),但是从不检查
    to\u int
    的结果类型。 这有一个有趣的结果:

    class X
      def to_int
        nil
      end
    
      def to_i
        42
      end
    end
    
    class Y
      def to_int
        false
      end
    
      def to_i
        42
      end
    end
    
    p Integer(X.new) #=> 42
    p Integer(Y.new) #=> false
    

    顺便说一句,我使用ruby 2.2.0(最新版本)得到了相同的结果。在
    1.9.2p0
    1.9.3p194
    2.0.0p195
    中得到了相同的结果。。。不要太认真,但是在
    IronRuby 1.0.0.0上:在这两种情况下
    Integer(…)
    都失败,
    String(…)
    给出
    “#”