2015-06-26 5 views
5

Мне нужно обработать значение хеша зависит от типа значения. Вот код с проблемой:Как обрабатывать тип значения хэш-функции в Perl XS

I32 keys = hv_iterinit(hash); 
for (I32 i = 0; i < keys; i++) 
{ 
    char *key = NULL; 
    I32 key_length = 0; 
    SV *value = hv_iternextsv(hash, &key, &key_length); 
    // SvROK(value); 
    if (SvTYPE(SvRV(value)) < SVt_PVAV) 
    { 
    // handle scalar 
    printf("key %s has scalar value\n", key); 
    } 
    else if (SvTYPE(SvRV(value)) == SVt_PVAV) 
    { 
    // handle array 
    printf("key %s has array value\n", key); 
    } 
    else if (SvTYPE(SvRV(value)) == SVt_PVHV) 
    { 
    // handle hash 
    printf("key %s has hash value\n", key); 
    } 
} 

Если я не использую прокомментированную строку, у меня есть проблема со скалярными значениями. Например, при следующем хэш {a => "b", c => {d => "e"}} является производить выход:

key c has hash value 
key d has scalar value 

Так вот мои вопросы:

  1. ли мы всегда ссылки вернулись из hv_iternextsv() или иногда возвращает скаляр?
  2. Почему я не вижу скалярного значения для ключа a.

Обновление.

Моя ошибка была связана с результатом hv_iternextsv(). Я думал, что это всегда ссылка. Вот как работает код выглядит следующим образом:

I32 keys = hv_iterinit(hash); 
for (I32 i = 0; i < keys; i++) 
{ 
    char *key = NULL; 
    I32 key_length = 0; 
    SV *value = hv_iternextsv(hash, &key, &key_length); 
    if (!SvROK(value)) 
    { 
    // handle scalar 
    } 
    else 
    { 
    if (SvTYPE(SvRV(value)) == SVt_PVAV) 
    { 
     // handle array 
    } 
    else if (SvTYPE(SvRV(value)) == SVt_PVHV) 
    { 
     // handle hash 
    } 
    } 
} 
+0

Я ожидаю, что ваша паста не хватает некоторых скобок, потому что не будет компилироваться. Возможно, вы имеете в виду: 'if (SvTYPE (SvRV (значение)) == SVt_PVAV)'? – LeoNerd

+0

Код обновлен, спасибо. –

+0

@ikegami Я обновил свой вопрос. Проблема в том, что я не вижу вывод скалярного значения для ключа 'a'. –

ответ

3

ли мы всегда ссылка, возвращенная из hv_iternextsv() или иногда возвращает скаляр?

Он всегда возвращает скаляр. Значения хэшей могут быть только скалярами. Эти скаляры могут быть ссылками ($h{x} = [];), но не обязательно ($h{y} = 123;).

Почему я не вижу скалярное значение для ключа a.

Там нет никакого способа, ваш мог бы вернуть то, что вы сказали, что делает, видя, как ваш хэш не имеет ключа с именем d. Для хэш предоставленной вами код выводит следующее:

key a has scalar value 
key c has hash value 

Но это скорее совпадение, чем все остальное, что вы получили правильный ответ. SvTYPE(SvRV(value)), когда value не является ссылкой ??? Это бессмысленно! Фиксированный код следующим образом:

use strict; 
use warnings; 

use Inline C => <<'__EOI__'; 

    void print_keys(HV* hash) { 
    char *key; 
    I32 key_length; 
    SV *value; 

    hv_iterinit(hash); 
    while (value = hv_iternextsv(hash, &key, &key_length)) { 
     if (SvROK(value)) { 
     SV * const referenced = SvRV(value); 
     if (SvTYPE(referenced) == SVt_PVAV) { 
      printf("The value at key %s is reference to an array\n", key); 
     } 
     else if (SvTYPE(referenced) == SVt_PVHV) { 
      printf("The value at key %s is a reference to a hash\n", key); 
     } 
     else { 
      printf("The value at key %s is a reference\n", key); 
     } 
     } else { 
     printf("The value at key %s is not a reference\n", key); 
     } 
    } 
    } 

__EOI__ 

print_keys({a => "b", c => {d => "e"}}); 

Выход:

The value at key a is not a reference 
The value at key c is a reference to a hash 
+0

Обновлен мой ответ. – ikegami

+0

Я снова вызываю этот код для хэша, поэтому он производит этот вывод. Я добавил контрольную проверку и показывает, что значение для ключа 'a' не является ссылкой.Поэтому мой второй вопрос все еще действителен. –

+0

Не лгите. На это был дан ответ, но вы изменили его через час. Если у вас есть новый вопрос, спросите его в комментариях или как вопрос по мере необходимости. // Вы можете проверить тип скаляра с помощью 'SvTYPE', но зачем вы хотите это сделать. Если вам нужна строка, используйте 'SvPVutf8'. Если вам нужно целое число, используйте 'SvIV' и т. Д. Вам все равно, как он хранится. – ikegami