2017-02-16 5 views
3

Я сохраняю простые значения (базовые типы данных) в хеш, и я вызываю dup на значение, прежде чем избегать воздействия на исходный объект (например, моментальный снимок). Я хочу не делать dup в случае немедленного значения и просто хранить его как есть. Можно ли определить, является ли объект/значение немедленным?Рубин: проверка на немедленное значение?

т.е. (12, 13, 14 являются непосредственными)

[12] pry(#<Table2Spec::TestTable>)> 1.dup 
TypeError: can't dup Fixnum 
from (pry):12:in `dup' 
[13] pry(#<Table2Spec::TestTable>)> :f.dup 
TypeError: can't dup Symbol 
from (pry):13:in `dup' 
[14] pry(#<Table2Spec::TestTable>)> true.dup 
TypeError: can't dup TrueClass 
from (pry):14:in `dup' 
[16] pry(#<Table2Spec::TestTable>)> 's'.dup 
=> "s" 

Согласно документации:

Immediate values are not passed by reference but are passed by value: nil, true, false, Fixnums, Symbols, and some Floats. 
+1

Ruby 2.4.0 позволяет обдувать немедленные объекты (хотя документы не были полностью обновлены). – matt

ответ

4

заимствование из Python, ЭСПЦ (проще попросить прощения, чем разрешения):

hash[key] = 
    begin 
    value.dup 
    rescue TypeError 
    value 
    end 
+0

Ruby 2.2.1 Версия одной линейки 'значение =" привет "; p begin value.dup rescue TypeError; «Opps» end' => '' Opps "'. Если вы развернете выражение в нескольких строках, то => '" hello "' – yeyo

+0

Спасибо вам большое. Я буду использовать эту логику, но не на одной строке, чтобы избежать проблемы, описанной @yeyo. Существует функция C rb_special_const_p, которая возвращает true, если значение не является указателем. Это приведет к тому, что метод #dup поднимет TypeError. Это удовлетворяет мои потребности. – abstractx1

+0

@yeyo: Вы совершенно правы, я не думал об этом :) – Amadan

2

Я не рекомендую это решение, но я помещаю это здесь:

MyProject/ 
ext 
└── core 
    ├── extconf.rb 
    └── core.c 

core.c

#include <ruby.h> 

VALUE Core = Qnil; 

void Init_core(); 
VALUE method_core_is_immediate(VALUE self, VALUE obj); 

void Init_core() { 
    Core = rb_define_module("Core"); 
    rb_define_singleton_method(Core, "is_immediate_value?", method_core_is_immediate, 1); 
} 

VALUE method_core_is_immediate(VALUE self, VALUE obj) { 
    if (rb_special_const_p(obj)) return (int)RUBY_Qtrue; 
    return (int)RUBY_Qfalse; 
} 

extconf.rb:

require 'mkmf' 
extension_name = 'core' 
dir_config(extension_name) 
create_makefile(extension_name) 

рубин:

require 'core' 

Core.is_immediate_value?(nil) #true 
Core.is_immediate_value?(true) #true 
Core.is_immediate_value?(:symb) #true 
Core.is_immediate_value?("string") #false 

Это может быть полезно кому-то. После изучения в течение нескольких часов я сделал это и, похоже, работает (просто способ вызвать rb_special_const_p). Было бы полезно, если бы был способ подтвердить немедленные значения, используя стандартную библиотеку ruby.

Смежные вопросы