Путаница с выводом `nil` при использовании `Symbol#‹=›` в Ruby

Symbol#<=>

просто говорит: сравнивает символ с other_symbol после вызова to_s для каждого из символов. Возвращает -1, 0, +1 или ноль в зависимости от того, меньше, равно или больше значение параметра other_symbol. nil возвращается, если два значения несопоставимы.

Я пытался понять, как работает Symbol#<=> при возврате nil. При этом я играл с кодом:

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

Из приведенного выше кода IRB я подумал, что возвращаемое значение будет 0. Но на самом деле это nil. Как говорится в документе, перед использованием <=> оператор to_s применяется как к RHO, так и к 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 не является объектом класса Symbol, будет возвращено nil. Давайте посмотрим кое-что еще в IRB:

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

Опять nil. Исходный код говорит, что rb_str_cmp_m(rb_sym_to_s(sym),rb_sym_to_s(other)) будет выполняться сейчас. Итак, теперь я пошел посмотреть исходный код STRING.C< /em>. Таким образом, мы в основном проезжаем 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);
}

Но приведенный выше код я не мог понять. Но я считаю, что в нем есть ответ, как nil производит, когда LHO не является объектом класса Symbol.

Может ли кто-нибудь помочь мне понять, как приходит nil, когда LHO не sym?


person Arup Rakshit    schedule 17.03.2013    source источник
comment
Посмотрите внимательно, не rb_str_cmp_m(rb_sym_to_s(sym), rb_sym_to_s(other)) ли возвращает nil строку выше: if (!SYMBOL_P(other)) { return Qnil; }   -  person fmendez    schedule 17.03.2013
comment
@fmendez да, внимательно посмотрите, что other это RHO. Я говорю о LHO. Сначала он проверяет RHO, если sym или нет. Если RHO равно sym, то он просто вызывает оператор return с вызовом to_s для обоих LHO and RHO.   -  person Arup Rakshit    schedule 17.03.2013
comment
Возможно, вы запутались, думая, что ‹=› является оператором (поэтому вы говорите о LHO и RHO). На самом деле это не оператор, это метод (поэтому вы должны говорить о получателе и аргументах). LHO является приемником. Я расширил свой ответ, чтобы уточнить.   -  person AlexChaffee    schedule 17.03.2013
comment
@AlexChaffee Да, я знаю, что это синтаксический сахар. Оставьте этот оператор, и просмотр исходного кода даст фактический ответ. Документ здесь немного сбивает с толку. исходный код - единственный вариант получить ответ :)   -  person Arup Rakshit    schedule 17.03.2013


Ответы (1)


Symbol и String — это разные типы, и поэтому они несопоставимы, как несопоставимы Fixnum и TrueClass. См. Почему символы не являются замороженными строками?, чтобы узнать, как они на самом деле < em>должен быть таким же (т. е. случай, когда класс Symbol наследуется от класса String).

В вашем первом примере метод <=> вызывается для символа, а аргументом является строка, поэтому sym_cmp возвращает nil.

Во втором примере метод <=> вызывается для строки, а аргумент является символом. Таким образом, rb_check_funcall видит, можно ли его естественным образом преобразовать в строку с помощью to_str; это невозможно ("NoMethodError: неопределенный метод to_str для :bar:Symbol"), поэтому (в конце концов) nil возвращается и в этом случае. (Нам нужно покопаться и посмотреть, что делает rb_invcmp, чтобы конкретизировать это «в конце концов» :-))

person AlexChaffee    schedule 17.03.2013
comment
Но как вы думаете, правильная ли документация для nil просмотра исходного кода. Я думаю, что документ не ясен. - person Arup Rakshit; 17.03.2013
comment
Когда я читаю исходный код C, он говорит, что если другой не является символом, верните nil, в противном случае преобразуйте их оба в строки и сравните их, что кажется правильным. - person AlexChaffee; 17.03.2013
comment
теперь ваше обновление находится на правильном пути. Я дал ссылку на github, вы можете использовать ее. - person Arup Rakshit; 17.03.2013