flatMap
или concatMap
, используя оператор flatMap
, вы можете сгладить подпоток в неблокирующей общедоступной
Flux<Object> test {
method1().flatMap(obj -> {
if (obj.getTotalItems() > 20) {
return method2(obj)
.map(result -> {
obj.setItems(result);
return obj;
});
}
return Mono.just(obj);
});
}
flatMap позволяет сгладить несколько потоков одновременно Таким образом, в случае длительных операций вы можете использовать более эффективные элементы процесса.
Одним из недостатков flatMap является то, что он не сохраняет порядок элементов, поэтому если у вас есть последовательность вышестоящих элементов, таких как [1, 2, 3, 4]
с flatMap
, есть вероятность, что порядок будет изменен из-за асинхронной природы подпотоков .
Чтобы сохранить порядок, вы можете использовать concatMap
, который выравнивает только один поток за раз, поэтому есть гарантии, что порядок элементов выравнивания будет сохранен:
Flux<Object> test {
method1().concatMap(obj -> {
if (obj.getTotalItems() > 20) {
return method2(obj)
.map(result -> {
obj.setItems(result);
return obj;
});
}
return Mono.just(obj);
});
}
Я боюсь, что C# не поддерживает частичную шаблонную специализацию.
Частичные шаблонные средства специализации:
У Вас есть базовый класс с двумя или больше шаблонами (дженерики / параметры типа). Параметры типа были бы <T, S>
В полученном (специализированном) классе Вы указываете на тип одного из параметров типа. Параметры типа могли быть похожими на это <T, интервал>.
Таким образом, то, когда кто-то использует (инстанцирует объекта), класс, где последний параметр типа является интервалом, производный класс используется.
D поддерживает частичную специализацию:
(сканирование для "частичного" в вышеупомянутых ссылках).
Вторая ссылка в особенности даст Вам очень подробную разбивку того, что можно сделать с шаблонной специализацией, не только в D, но и в C++ также.
Вот определенный пример D swap
. Это должно распечатать сообщение для подкачки, специализированной для Thing
класс.
import std.stdio; // for writefln
// Class with swap method
class Thing(T)
{
public:
this(T thing)
{
this.thing = thing;
}
// Implementation is the same as generic swap, but it will be called instead.
void swap(Thing that)
{
const T tmp = this.thing;
this.thing = that.thing;
that.thing = tmp;
}
public:
T thing;
}
// Swap generic function
void swap(T)(ref T lhs, ref T rhs)
{
writefln("Generic swap.");
const T tmp = lhs;
lhs = rhs;
rhs = tmp;
}
void swap(T : Thing!(U))(ref T lhs, ref T rhs)
{
writefln("Specialized swap method for Things.");
lhs.swap(rhs);
}
// Test case
int main()
{
auto v1 = new Thing!(int)(10);
auto v2 = new Thing!(int)(20);
assert (v1.thing == 10);
assert (v2.thing == 20);
swap(v1, v2);
assert (v1.thing == 20);
assert (v2.thing == 10);
return 0;
}
У Haskell есть перекрывающиеся экземпляры как расширение:
class Sizable a where
size :: a -> Int
instance Collection c => Sizable c where
size = length . toList
функция состоит в том, чтобы найти размер какого-либо набора, который может иметь более определенные экземпляры:
instance Sizable (Seq a) where
size = Seq.length
C#:
void Swap<T>(ref T a, ref T b) {
var c = a;
a = b;
b = c;
}
Я предполагаю, что (чистая) Haskell-версия была бы:
swap :: a -> b -> (b,a)
swap a b = (b, a)
На самом деле Вы можете (не совсем; посмотрите ниже), делают это в C# с дополнительными методами:
public Count (this IEnumerable<T> seq) {
int n = 0;
foreach (T t in seq)
n++;
return n;
}
public Count (this T[] arr) {
return arr.Length;
}
Затем вызов array.Count()
будет использовать специализированную версию. "Не совсем" то, потому что разрешение зависит от статического типа array
, не на типе выполнения. Т.е. это будет использовать более общую версию:
IEnumerable<int> array = SomethingThatReturnsAnArray();
return array.Count();
Java имеет дженерики, которые позволяют Вам делать подобные виды вещей.