класс 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.
- Tms
-
Tmsдля обратной совместимости
Общедоступные методы класса
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.
Если имя класса (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 и struct ссылаются на один и тот же ключ хеша, если у них одинаковый подкласс структуры и равные значения членов (согласно Object#eql?).
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.
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 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;
} Вызывает блок для каждого значения члена структуры и возвращает массив, содержащий значения членов структуры, для которых блок возвращает значение 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));
} Возвращает значения этой структуры как массив.
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;
} Возвращает хеш, содержащий имена и значения членов структуры.
Если указан блок, результаты блока для каждой пары получателя будут использоваться как пары.
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"
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 или диапазоном смещений (как в 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.