класс Struct
Класс Struct — удобный способ объединить несколько атрибутов вместе, используя методы доступа, без необходимости написания явного класса.
Класс Struct генерирует новые подклассы, которые содержат набор членов и их значения. Для каждого члена создаётся метод чтения и записи, аналогично методу Module#attr_accessor.
Customer = Struct.new(:name, :address) do
def greeting
"Hello #{name}!"
end
end
dave = Customer.new("Dave", "123 Main")
dave.name #=> "Dave"
dave.greeting #=> "Hello Dave!"
См. ::new для дополнительных примеров создания подклассов и экземпляров структур.
В описаниях методов, что следуют далее, параметр «member» относится к члену структуры, который является либо строкой в кавычках ("name") или символом (:name).
Константы
- Group
-
Group — это структура Struct, доступная только при компиляции с
HAVE_GETGRENT.Структура содержит следующие члены:
- name
-
содержит имя группы как строку.
- passwd
-
содержит зашифрованный пароль как строку. Возвращает 'x', если доступ к паролю группы недоступен; возвращает пустую строку, если для получения членства в группе пароль не нужен.
Требует компиляции с
HAVE_STRUCT_GROUP_GR_PASSWD. - gid
-
содержит числовой идентификатор группы как целое число.
- mem
-
является массивом строк, содержащих короткие логины членов группы.
- Passwd
-
Passwd — структура Struct, содержащая следующие члены:
- name
-
содержит короткий логин пользователя как строку.
- passwd
-
содержит зашифрованный пароль пользователя как строку. Возвращает 'x', если используются теневые пароли. Возвращает '*', если пользователь не может войти с помощью пароля.
- uid
-
содержит целочисленный идентификатор пользователя (uid).
- gid
-
содержит целочисленный идентификатор группы (gid) основной группы пользователя.
- dir
-
содержит путь к домашнему каталогу пользователя как строку.
- shell
-
содержит путь к логин-оболочке пользователя как строку.
Следующие члены ниже являются необязательными и должны быть скомпилированы со специальными флагами:
- gecos
-
содержит более длинное описание пользователя, такое как полное имя. Некоторые Unix-системы предоставляют структурированную информацию в поле gecos, но это зависит от системы. Требует компиляции с
HAVE_STRUCT_PASSWD_PW_GECOS - change
-
время смены пароля (целое число). Требует компиляции с
HAVE_STRUCT_PASSWD_PW_CHANGE - quota
-
значение квоты (целое число). Требует компиляции с
HAVE_STRUCT_PASSWD_PW_QUOTA - age
-
возраст пароля (целое число). Требует компиляции с
HAVE_STRUCT_PASSWD_PW_AGE - class
-
класс доступа пользователя (строка). Требует компиляции с
HAVE_STRUCT_PASSWD_PW_CLASS - comment
-
комментарий (строка). Требует компиляции с
HAVE_STRUCT_PASSWD_PW_COMMENT - expire
-
время истечения срока действия аккаунта (целое число). Требует компиляции с
HAVE_STRUCT_PASSWD_PW_EXPIRE
- Tms
Публичные методы класса
# File ext/json/lib/json/add/struct.rb, line 10 def self.json_create(object) new(*object['v']) end
Десериализует строку JSON, создавая новый объект Struct со значениями v сериализованными с помощью to_json.
static VALUE
rb_struct_s_def(int argc, VALUE *argv, VALUE klass)
{
VALUE name, rest, keyword_init;
long i;
VALUE st;
st_table *tbl;
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
name = argv[0];
if (SYMBOL_P(name)) {
name = Qnil;
}
else {
--argc;
++argv;
}
if (RB_TYPE_P(argv[argc-1], T_HASH)) {
VALUE kwargs[1];
static ID keyword_ids[1];
if (!keyword_ids[0]) {
keyword_ids[0] = rb_intern("keyword_init");
}
rb_get_kwargs(argv[argc-1], keyword_ids, 0, 1, kwargs);
--argc;
keyword_init = kwargs[0];
}
else {
keyword_init = Qfalse;
}
rest = rb_ident_hash_new();
RBASIC_CLEAR_CLASS(rest);
tbl = RHASH_TBL(rest);
for (i=0; i<argc; i++) {
VALUE mem = rb_to_symbol(argv[i]);
if (st_insert(tbl, mem, Qtrue)) {
rb_raise(rb_eArgError, "duplicate member: %"PRIsVALUE, mem);
}
}
rest = rb_hash_keys(rest);
st_clear(tbl);
RBASIC_CLEAR_CLASS(rest);
OBJ_FREEZE_RAW(rest);
if (NIL_P(name)) {
st = anonymous_struct(klass);
}
else {
st = new_struct(name, klass);
}
setup_struct(st, rest);
rb_ivar_set(st, id_keyword_init, keyword_init);
if (rb_block_given_p()) {
rb_mod_module_eval(0, 0, st);
}
return st;
} Первые два формата используются для создания нового подкласса Struct class_name, который может содержать значение для каждого member_name. Этот подкласс может использоваться для создания экземпляров структуры, как любой другой класс.
Если class_name опущено, будет создан анонимный класс структуры. В противном случае имя этой структуры появится как константа в классе Struct, поэтому оно должно быть уникальным для всех структур в системе и должно начинаться с заглавной буквы. Присвоение классу структуры константе также даёт классу имя константы.
# Create a structure with a name under Struct
Struct.new("Customer", :name, :address)
#=> Struct::Customer
Struct::Customer.new("Dave", "123 Main")
#=> #<struct Struct::Customer name="Dave", address="123 Main">
# Create a structure named by its constant
Customer = Struct.new(:name, :address)
#=> Customer
Customer.new("Dave", "123 Main")
#=> #<struct Customer name="Dave", address="123 Main">
Если необязательный аргумент keyword_init установлен в true, .new принимает ключевые аргументы вместо обычных аргументов.
Customer = Struct.new(:name, :address, keyword_init: true) Customer.new(name: "Dave", address: "123 Main") #=> #<struct Customer name="Dave", address="123 Main">
Если задан блок, он будет вычислен в контексте StructClass, передавая созданный класс в качестве параметра:
Customer = Struct.new(:name, :address) do
def greeting
"Hello #{name}!"
end
end
Customer.new("Dave", "123 Main").greeting #=> "Hello Dave!"
Это рекомендуемый способ настройки структуры. Наследование от анонимной структуры создаёт дополнительный анонимный класс, который никогда не будет использован.
Последние два формата создают новый экземпляр подкласса структуры. Количество value параметров должно быть меньше или равно количеству атрибутов, определённых для структуры. Неустановленные параметры принимают значения по умолчанию nil. Передача большего количества параметров, чем число атрибутов, вызовет исключение ArgumentError.
Customer = Struct.new(:name, :address)
Customer.new("Dave", "123 Main")
#=> #<struct Customer name="Dave", address="123 Main">
Customer["Dave"]
#=> #<struct Customer name="Dave", address=nil>
Методы публичного экземпляра
static VALUE
rb_struct_equal(VALUE s, VALUE s2)
{
if (s == s2) return Qtrue;
if (!RB_TYPE_P(s2, T_STRUCT)) return Qfalse;
if (rb_obj_class(s) != rb_obj_class(s2)) return Qfalse;
if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) {
rb_bug("inconsistent struct"); /* should never happen */
}
return rb_exec_recursive_paired(recursive_equal, s, s2, s2);
} Равенство — Возвращает true , если other имеет тот же подкласс структуры и имеет равные значения членов (в соответствии с Object#==).
Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joejr = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
jane = Customer.new("Jane Doe", "456 Elm, Anytown NC", 12345)
joe == joejr #=> true
joe == jane #=> false
VALUE
rb_struct_aref(VALUE s, VALUE idx)
{
int i = rb_struct_pos(s, &idx);
if (i < 0) invalid_struct_pos(s, idx);
return RSTRUCT_GET(s, i);
} Ссылка на атрибут — Возвращает значение заданного члена структуры member или члена по заданному index. Вызывает NameError, если member не существует, и IndexError, если index находится вне диапазона.
Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe["name"] #=> "Joe Smith"
joe[:name] #=> "Joe Smith"
joe[0] #=> "Joe Smith"
VALUE
rb_struct_aset(VALUE s, VALUE idx, VALUE val)
{
int i = rb_struct_pos(s, &idx);
if (i < 0) invalid_struct_pos(s, idx);
rb_struct_modify(s);
RSTRUCT_SET(s, i, val);
return val;
} Присваивание атрибута — Устанавливает значение заданного члена структуры member или члена по заданному index. Вызывает NameError, если member не существует, и IndexError, если index находится вне диапазона.
Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe["name"] = "Luke"
joe[:zip] = "90210"
joe.name #=> "Luke"
joe.zip #=> "90210"
# File ext/json/lib/json/add/struct.rb, line 16
def as_json(*)
klass = self.class.name
klass.to_s.empty? and raise JSON::JSONError, "Only named structs are supported!"
{
JSON.create_id => klass,
'v' => values,
}
end Возвращает хеш, который будет преобразован в объект JSON и представит этот объект.
static VALUE
rb_struct_dig(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
self = rb_struct_lookup(self, *argv);
if (!--argc) return self;
++argv;
return rb_obj_dig(argc, argv, self, Qnil);
} Извлекает вложенное значение, указанное последовательностью key объектов, вызывая dig на каждом шаге, возвращая nil , если любой промежуточный шаг является nil.
Foo = Struct.new(:a)
f = Foo.new(Foo.new({b: [1, 2, 3]}))
f.dig(:a, :a, :b, 0) # => 1
f.dig(:b, 0) # => nil
f.dig(:a, :a, :b, :c) # TypeError: no implicit conversion of Symbol into Integer
static VALUE
rb_struct_each(VALUE s)
{
long i;
RETURN_SIZED_ENUMERATOR(s, 0, 0, struct_enum_size);
for (i=0; i<RSTRUCT_LEN(s); i++) {
rb_yield(RSTRUCT_GET(s, i));
}
return s;
} Возвращает значение каждого члена структуры в порядке. Если блок не указан, возвращается перечислитель.
Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe.each {|x| puts(x) }
Результат:
Joe Smith 123 Maple, Anytown NC 12345
static VALUE
rb_struct_each_pair(VALUE s)
{
VALUE members;
long i;
RETURN_SIZED_ENUMERATOR(s, 0, 0, struct_enum_size);
members = rb_struct_members(s);
if (rb_block_arity() > 1) {
for (i=0; i<RSTRUCT_LEN(s); i++) {
VALUE key = rb_ary_entry(members, i);
VALUE value = RSTRUCT_GET(s, i);
rb_yield_values(2, key, value);
}
}
else {
for (i=0; i<RSTRUCT_LEN(s); i++) {
VALUE key = rb_ary_entry(members, i);
VALUE value = RSTRUCT_GET(s, i);
rb_yield(rb_assoc_new(key, value));
}
}
return s;
} Возвращает имя и значение каждого члена структуры в порядке. Если блок не указан, возвращается перечислитель.
Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe.each_pair {|name, value| puts("#{name} => #{value}") }
Результат:
name => Joe Smith address => 123 Maple, Anytown NC zip => 12345
static VALUE
rb_struct_eql(VALUE s, VALUE s2)
{
if (s == s2) return Qtrue;
if (!RB_TYPE_P(s2, T_STRUCT)) return Qfalse;
if (rb_obj_class(s) != rb_obj_class(s2)) return Qfalse;
if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) {
rb_bug("inconsistent struct"); /* should never happen */
}
return rb_exec_recursive_paired(recursive_eql, s, s2, s2);
} Равенство Hash — other и struct ссылаются на один и тот же ключ хеша, если они имеют тот же подкласс структуры и имеют равные значения членов (в соответствии с Object#eql?).
static VALUE
rb_struct_hash(VALUE s)
{
long i, len;
st_index_t h;
VALUE n;
const VALUE *ptr;
h = rb_hash_start(rb_hash(rb_obj_class(s)));
ptr = RSTRUCT_CONST_PTR(s);
len = RSTRUCT_LEN(s);
for (i = 0; i < len; i++) {
n = rb_hash(ptr[i]);
h = rb_hash_uint(h, NUM2LONG(n));
}
h = rb_hash_end(h);
return INT2FIX(h);
} Возвращает значение хеша, основанное на содержимом этой структуры.
См. также Object#hash.
static VALUE
rb_struct_inspect(VALUE s)
{
return rb_exec_recursive(inspect_struct, s, 0);
} Возвращает описание этой структуры в виде строки.
VALUE
rb_struct_size(VALUE s)
{
return LONG2FIX(RSTRUCT_LEN(s));
} Возвращает количество членов структуры.
Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe.length #=> 3
static VALUE
rb_struct_members_m(VALUE obj)
{
return rb_struct_s_members_m(rb_obj_class(obj));
} Возвращает члены структуры как массив символов:
Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe.members #=> [:name, :address, :zip]
static VALUE
rb_struct_select(int argc, VALUE *argv, VALUE s)
{
VALUE result;
long i;
rb_check_arity(argc, 0, 0);
RETURN_SIZED_ENUMERATOR(s, 0, 0, struct_enum_size);
result = rb_ary_new();
for (i = 0; i < RSTRUCT_LEN(s); i++) {
if (RTEST(rb_yield(RSTRUCT_GET(s, i)))) {
rb_ary_push(result, RSTRUCT_GET(s, i));
}
}
return result;
} Передает каждое значение члена структуры в блок и возвращает массив, содержащий значения членов из struct , для которых заданный блок возвращает значение true (эквивалентно Enumerable#select).
Lots = Struct.new(:a, :b, :c, :d, :e, :f)
l = Lots.new(11, 22, 33, 44, 55, 66)
l.select {|v| v.even? } #=> [22, 44, 66]
VALUE
rb_struct_size(VALUE s)
{
return LONG2FIX(RSTRUCT_LEN(s));
} Возвращает количество членов структуры.
Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe.length #=> 3
static VALUE
rb_struct_to_a(VALUE s)
{
return rb_ary_new4(RSTRUCT_LEN(s), RSTRUCT_CONST_PTR(s));
} Возвращает значения для этой структуры в виде массива.
Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe.to_a[1] #=> "123 Maple, Anytown NC"
static VALUE
rb_struct_to_h(VALUE s)
{
VALUE h = rb_hash_new_with_size(RSTRUCT_LEN(s));
VALUE members = rb_struct_members(s);
long i;
for (i=0; i<RSTRUCT_LEN(s); i++) {
rb_hash_aset(h, rb_ary_entry(members, i), RSTRUCT_GET(s, i));
}
return h;
} Возвращает хеш, содержащий имена и значения членов структуры.
Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe.to_h[:address] #=> "123 Maple, Anytown NC"
static VALUE
rb_struct_to_a(VALUE s)
{
return rb_ary_new4(RSTRUCT_LEN(s), RSTRUCT_CONST_PTR(s));
} Возвращает значения для этой структуры в виде массива.
Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe.to_a[1] #=> "123 Maple, Anytown NC"
static VALUE
rb_struct_values_at(int argc, VALUE *argv, VALUE s)
{
return rb_get_values_at(s, RSTRUCT_LEN(s), argc, argv, struct_entry);
} Возвращает значения членов структуры для каждого selector в виде массива. selector может быть либо смещением типа Integer, либо диапазоном смещений типа Range (как в Array#values_at).
Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe.values_at(0, 2) #=> ["Joe Smith", 12345]
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.