PECS (сокращение от «Производитель extends
и Consumer super
») объясняется: принципом «Get and Put»
Указывает, что
1. For Extends Wildcard (получить значения, т. Е. Producer extends
)
Вот метод, который берет набор чисел, преобразует каждый в double
и суммирует их вверх
public static double sum(Collection<? extends Number> nums) {
double s = 0.0;
for (Number num : nums)
s += num.doubleValue();
return s;
}
Назовем метод:
List<Integer>ints = Arrays.asList(1,2,3);
assert sum(ints) == 6.0;
List<Double>doubles = Arrays.asList(2.78,3.14);
assert sum(doubles) == 5.92;
List<Number>nums = Arrays.<Number>asList(1,2,2.78,3.14);
assert sum(nums) == 8.92;
Поскольку метод sum()
использует extends
, все следующие вызовы являются законными. Первые два вызова не были бы законными, если бы расширения не использовались.
ИСКЛЮЧЕНИЕ : вы не можете помещать что-либо в тип, объявленный с помощью подстановочного знака extends
, за исключением значения null
, который относится к каждому ссылочному типу:
List<Integer> ints = new ArrayList<Integer>();
ints.add(1);
ints.add(2);
List<? extends Number> nums = ints;
nums.add(null); // ok
assert nums.toString().equals("[1, 2, null]");
2. Для Super Wildcard (put values ie Consumer super
)
Вот метод, который принимает набор чисел и int n
, и помещает первые n
целые числа, начиная с нуля, в сбор:
public static void count(Collection<? super Integer> ints, int n) {
for (int i = 0; i < n; i++) ints.add(i);
}
Давайте назовем метод:
List<Integer>ints = new ArrayList<Integer>();
count(ints, 5);
assert ints.toString().equals("[0, 1, 2, 3, 4]");
List<Number>nums = new ArrayList<Number>();
count(nums, 5); nums.add(5.0);
assert nums.toString().equals("[0, 1, 2, 3, 4, 5.0]");
List<Object>objs = new ArrayList<Object>();
count(objs, 5); objs.add("five");
assert objs.toString().equals("[0, 1, 2, 3, 4, five]");
Поскольку метод count()
использует super
, все следующие звонки законны: последние два вызова не были бы законными, если бы супер не использовался.
ИСКЛЮЧЕНИЕ : вы не можете получить что-либо из типа, объявленного с помощью super
за исключением значения типа Object
, которое является супертипом каждого ссылочного типа:
List<Object> objs = Arrays.<Object>asList(1,"two");
List<? super Integer> ints = objs;
String str = "";
for (Object obj : ints) str += obj.toString();
assert str.equals("1two");
3. Когда оба Get и Put, не используйте wildcard
. Когда вы оба вставляете значения и получаете значения из одной и той же структуры, вы не должны использовать подстановочный знак.
public static double sumCount(Collection<Number> nums, int n) {
count(nums, n);
return sum(nums);
}
Без коллизий можно сделать
M = [fieldnames(A)' fieldnames(B)'; struct2cell(A)' struct2cell(B)'];
C=struct(M{:});
, И это довольно эффективно. Однако struct
ошибки на дублирующихся именах полей, и предварительно проверяющий на них использующий unique
уничтожают производительность до такой степени, что цикл лучше. Но вот то, на что это было бы похоже:
M = [fieldnames(A)' fieldnames(B)'; struct2cell(A)' struct2cell(B)'];
[tmp, rows] = unique(M(1,:), 'last');
M=M(:, rows);
C=struct(M{:});
Вы могли бы быть в состоянии сделать гибридное решение, не принимая конфликтов и используя попытку/выгоду вокруг вызова к struct
для корректного ухудшения к случаю обработки конфликта.
Я нашел хорошее решение для обмена файлами: catstruct .
Без тестирования производительности могу сказать, что он сделал именно то, что хотел. Конечно, он может работать с дублирующимися полями.
Вот как это работает:
a.f1 = 1;
a.f2 = 2;
b.f2 = 3;
b.f4 = 4;
s = catstruct(a,b)
даст
s =
f1: 1
f2: 3
f3: 4
Я не думаю, что вы можете справиться с конфликтами без петель, и я не думаю, что вам нужно их избегать. (хотя я полагаю, что эффективность может быть проблемой со многими областями ...)
Я использую функцию, которую я написал несколько лет назад, под названием setdefaults.m
, которая объединяет одну структуру со значениями другой структуры, где один имеет приоритет над другим в случае конфликта.
% SETDEFAULTS sets the default structure values
% SOUT = SETDEFAULTS(S, SDEF) reproduces in S
% all the structure fields, and their values, that exist in
% SDEF that do not exist in S.
% SOUT = SETDEFAULTS(S, SDEF, OVERRIDE) does
% the same function as above, but if OVERRIDE is 1,
% it copies all fields of SDEF to SOUT.
function sout = setdefaults(s,sdef,override)
if (not(exist('override','var')))
override = 0;
end
sout = s;
for f = fieldnames(sdef)'
cf = char(f);
if (override | not(isfield(sout,cf)))
sout = setfield(sout,cf,getfield(sdef,cf));
end
end
Теперь, когда я думаю об этом, я почти уверен, что вход «переопределить» не нужен (вы можете просто изменить порядок входов), хотя я не уверен на 100% в этом ... Итак, вот более простое переписывание (setdefaults2.m
):
% SETDEFAULTS2 sets the default structure values
% SOUT = SETDEFAULTS(S, SDEF) reproduces in S
% all the structure fields, and their values, that exist in
% SDEF that do not exist in S.
function sout = setdefaults2(s,sdef)
sout = sdef;
for f = fieldnames(s)'
sout = setfield(sout,f{1},getfield(s,f{1}));
end
и некоторые образцы для его проверки:
>> S1 = struct('a',1,'b',2,'c',3);
>> S2 = struct('b',4,'c',5,'d',6);
>> setdefaults2(S1,S2)
ans =
b: 2
c: 3
d: 6
a: 1
>> setdefaults2(S2,S1)
ans =
a: 1
b: 4
c: 5
d: 6
В C структура может иметь другую структуру как один из, его - участники. В то время как это не точно то же как, что Вы спрашиваете, Вы могли закончить или с ситуацией, где одна структура содержит другого, или одна структура содержит две структуры, обе из которых содержат части информации, которую Вы хотели.
psuedocode: я не помню фактический синтаксис.
A.field1 = 1;
A.field2 = 'a';
A.field3 = struct B;
для доступа: field3.field4;
или что-то вроде этого.
Или у Вас могла быть структура C, содержат и A и B:
C.A = struct A;
C.B = struct B;
с доступом тогда что-то как
C.A.field1;
C.A.field2;
C.B.field3;
C.B.field4;
надежда это помогает!
РЕДАКТИРОВАНИЕ: оба из этих решений стараются не называть коллизии.
кроме того, я не видел Ваш matlab
тег. Условно, необходимо хотеть отредактировать вопрос включать ту часть информации