класс 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!"
См. Struct::new для дополнительных примеров создания подклассов и экземпляров структур.
В описаниях методов параметр «член» относится к члену структуры, который является либо строкой в кавычках ("name") или Symbol (:name).
Константы
- Group
-
Group— структура (Struct), доступная только при компиляции сHAVE_GETGRENT.Структура содержит следующие члены:
- name
-
содержит имя группы как
String. - passwd
-
содержит зашифрованный пароль как
String. Возвращает 'x', если доступ к паролю группы недоступен; возвращает пустую строку, если для получения членства в группе пароль не требуется.Необходимо компилировать с
HAVE_STRUCT_GROUP_GR_PASSWD. - gid
-
содержит числовой идентификатор группы как целое число.
- mem
-
является
Arrayстрок, содержащих короткие имена входа членов группы.
- Passwd
-
Passwd— структура (Struct), содержащая следующие члены:- name
-
содержит короткое имя входа пользователя как
String. - passwd
-
содержит зашифрованный пароль пользователя как
String. Возвращает 'x', если используются теневые пароли. Возвращает '*', если пользователь не может войти с паролем. - uid
-
содержит целочисленный идентификатор пользователя (uid).
- gid
-
содержит целочисленный идентификатор группы (gid) основной группы пользователя.
- dir
-
содержит путь к домашнему каталогу пользователя как
String. - shell
-
содержит путь к командному интерпретатору входа пользователя как
String.
Следующие члены необязательны и должны быть скомпилированы со специальными флагами:
- gecos
-
содержит более подробное описание пользователя, например, полное имя, как
String. Некоторые системы 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.
Публичные методы класса
static VALUE
rb_struct_s_def(int argc, VALUE *argv, VALUE klass)
{
VALUE name, rest, keyword_init = Qfalse;
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)) {
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, &keyword_init);
if (keyword_init == Qundef) {
keyword_init = Qfalse;
}
--argc;
}
rest = rb_ident_hash_new();
RBASIC_CLEAR_CLASS(rest);
OBJ_WB_UNPROTECT(rest);
tbl = RHASH_TBL_RAW(rest);
for (i=0; i<argc; i++) {
VALUE mem = rb_to_symbol(argv[i]);
if (rb_is_attrset_sym(mem)) {
rb_raise(rb_eArgError, "invalid struct member: %"PRIsVALUE, mem);
}
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.
Если 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 и представляет этот объект.
Возвращает значения для этой структуры в виде массива Array.
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_deconstruct_keys(VALUE s, VALUE keys)
{
VALUE h;
long i;
if (NIL_P(keys)) {
return rb_struct_to_h(s);
}
if (UNLIKELY(!RB_TYPE_P(keys, T_ARRAY))) {
rb_raise(rb_eTypeError,
"wrong argument type %"PRIsVALUE" (expected Array or nil)",
rb_obj_class(keys));
}
if (RSTRUCT_LEN(s) < RARRAY_LEN(keys)) {
return rb_hash_new_with_size(0);
}
h = rb_hash_new_with_size(RARRAY_LEN(keys));
for (i=0; i<RARRAY_LEN(keys); i++) {
VALUE key = RARRAY_AREF(keys, i);
int i = rb_struct_pos(s, &key);
if (i < 0) {
return h;
}
rb_hash_aset(h, key, RSTRUCT_GET(s, i));
}
return h;
} 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 и identifiers. Вложенные объекты могут быть экземплярами различных классов. См. Методы Dig.
Примеры:
Foo = Struct.new(:a)
f = Foo.new(Foo.new({b: [1, 2, 3]}))
f.dig(:a) # => #<struct Foo a={:b=>[1, 2, 3]}>
f.dig(:a, :a) # => {:b=>[1, 2, 3]}
f.dig(:a, :a, :b) # => [1, 2, 3]
f.dig(:a, :a, :b, 0) # => 1
f.dig(:b, 0) # => nil
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_pair_yield_optimizable()) {
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?).
Возвращает каждый член структуры в блок и возвращает массив, содержащий члены структуры, для которых указанный блок возвращает значение 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]
Struct#filter является псевдонимом для Struct#select.
static VALUE
rb_struct_hash(VALUE s)
{
long i, len;
st_index_t h;
VALUE n;
h = rb_hash_start(rb_hash(rb_obj_class(s)));
len = RSTRUCT_LEN(s);
for (i = 0; i < len; i++) {
n = rb_hash(RSTRUCT_GET(s, i));
h = rb_hash_uint(h, NUM2LONG(n));
}
h = rb_hash_end(h);
return ST2FIX(h);
} Возвращает значение хеша, основанное на содержимом этой структуры.
См. также Object#hash.
static VALUE
rb_struct_inspect(VALUE s)
{
return rb_exec_recursive(inspect_struct, s, 0);
} Возвращает описание этой структуры в виде строки.
Возвращает количество членов структуры.
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;
} Возвращает каждый член структуры в блок и возвращает массив, содержащий члены структуры, для которых указанный блок возвращает значение 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]
Struct#filter является псевдонимом для Struct#select.
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));
} Возвращает значения для этой структуры в виде массива Array.
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;
int block_given = rb_block_given_p();
for (i=0; i<RSTRUCT_LEN(s); i++) {
VALUE k = rb_ary_entry(members, i), v = RSTRUCT_GET(s, i);
if (block_given)
rb_hash_set_pair(h, rb_yield_values(2, k, v));
else
rb_hash_aset(h, k, v);
}
return h;
} Возвращает Hash, содержащий имена и значения членов структуры.
Если блок задан, результаты блока для каждой пары будут использоваться в качестве пар.
Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe.to_h[:address] #=> "123 Maple, Anytown NC"
joe.to_h{|name, value| [name.upcase, value.to_s.upcase]}[:ADDRESS]
#=> "123 MAPLE, ANYTOWN NC"
Возвращает значения для этой структуры в виде Array.
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 в виде Array. Селектор может быть смещением 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–2020 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.