1

Symbol#<=>

简单地说:在每个符号上调用 to_s 后将符号与 other_symbol 进行比较。根据 symbol 是否小于、等于或大于 other_symbol,返回 -1、0、+1 或 nil。nil如果两个值不可比较,则返回。

我试图了解Symbol#<=>返回时的工作原理nil。这样做我玩了代码:

>> :x.to_s
=> "x"
>> 'x'.to_s
=> "x"

从上面的IRB代码我认为返回值将是0. 但实际是nil。正如文档所说,在使用<=>运算符之前to_s应用了RHOand LHO。但是在我看来,下面的代码不支持该原则。

>> :x <=> "x"
#=> nil

所以我试图查看源代码,来回答自己:

static VALUE
sym_cmp(VALUE sym, VALUE other)
{
    if (!SYMBOL_P(other)) {
        return Qnil;
    }
    return rb_str_cmp_m(rb_sym_to_s(sym), rb_sym_to_s(other));
}

查看源代码很明显,如果RHO不是 class 的对象Symbolnil将返回。让我们看看 IRB 中的更多内容:

>> "x" <=> :x
#=> nil

再次nil。说rb_str_cmp_m(rb_sym_to_s(sym),rb_sym_to_s(other))现在将执行的源代码。所以现在我去看了STRING.C. 所以我们基本上是通过rb_str_cmp_m(???,"x"). 现在我从 github 找到了:(?意味着不知道什么值)

rb_str_cmp_m(VALUE str1, VALUE str2)
{
    int result;

    if (!RB_TYPE_P(str2, T_STRING)) {
VALUE tmp = rb_check_funcall(str2, rb_intern("to_str"), 0, 0);
if (RB_TYPE_P(tmp, T_STRING)) {
result = rb_str_cmp(str1, tmp);
}
else {
return rb_invcmp(str1, str2);
}
    }
    else {
result = rb_str_cmp(str1, str2);
    }
    return INT2FIX(result);
}

但是上面的代码我无法理解。但我相信它有答案当不是 class 的对象nil时是如何产生的。LHOSymbol

任何人都可以在这里帮助我了解什么nil时候LHO不来sym吗?

4

1 回答 1

3

Symbol 和 String 是不同的类型,因此不可比,就像 Fixnum 和 TrueClass 不可比一样。请参阅为什么符号不是冻结字符串?关于它们实际上应该如何相同的咆哮(即,使类 Symbol 继承自类 String 的情况)。

在您的第一个示例中,该方法<=>是在一个符号上调用的,并且参数是一个字符串,因此sym_cmp返回 nil。

在您的第二个示例中,<=>正在对字符串调用该方法,并且参数是一个符号。所以rb_check_funcall看它是否可以使用to_str;自然地转换成字符串。它不能(“NoMethodError: undefined method to_strfor :bar:Symbol”),所以(最终)nil在这种情况下也会返回。(我们必须深入研究,看看是什么rb_invcmp让“最终”充实起来:-))

于 2013-03-17T12:28:37.400 回答