Лямбда-выражения обычно используются для инкапсуляции алгоритмов, чтобы они могли быть переданы другой функции. Тем не менее, можно выполнить лямбда сразу после определения:
[&](){ ...your code... }(); // immediately executed lambda expression
функционально эквивалентен
{ ...your code... } // simple code block
. Это делает лямбда-выражения мощным инструментом для реорганизации сложных функций. Вы начинаете с упаковки раздела кода в лямбда-функции, как показано выше. Затем процесс явной параметризации можно выполнить постепенно с промежуточным тестированием после каждого шага. После полной настройки кодового блока (как показано в результате удаления &
), вы можете переместить код во внешнее местоположение и сделать его нормальной функцией.
Аналогичным образом вы можете использовать лямбда-выражения для инициализации переменных на основе результата алгоритма ...
int a = []( int b ){ int r=1; while (b>0) r*=b--; return r; }(5); // 5!
Как способ разбиения вашей логики на программу, вы можете даже счесть полезным передать лямбда-выражение в качестве аргумента другому lambda expression ...
[&]( std::function algorithm ) // wrapper section
{
...your wrapper code...
algorithm();
...your wrapper code...
}
([&]() // algorithm section
{
...your algorithm code...
});
Лямбда-выражения также позволяют создавать именованные вложенные функции , что может быть удобным способом избежать дублирования логики. Использование именованных lambdas также имеет тенденцию быть немного легче на глазах (по сравнению с анонимными встроенными лямбдами) при передаче нетривиальной функции в качестве параметра другой функции. Примечание: не забывайте точку с запятой после закрывающей фигурной скобки.
auto algorithm = [&]( double x, double m, double b ) -> double
{
return m*x+b;
};
int a=algorithm(1,2,3), b=algorithm(4,5,6);
Если последующее профилирование показывает значительные служебные издержки инициализации для объекта функции, вы можете переписать это как нормальная функция.
Вот метод расширения, который я использую, чтобы обойти это невероятно разочаровывающее решение. Смотрите примечания, лучший и наиболее эффективный способ справиться с этим - использовать конструктор ticks из DateTimeOffset
вместо того, чтобы выделять другое промежуточное звено DateTime
просто для изменения его свойства Kind
.
/// <summary>
/// Converts a DateTime to a DateTimeOffset, without risking any onerous exceptions
/// the framework quite unfortunately throws within the DateTimeOffset constructor,
/// such as they do when the source DateTime's Kind is not set to UTC. The best and
/// most performant way around this, which we do herein, is to simply construct the
/// new DateTimeOffset with the overload that excepts Ticks. Also, we will simply
/// return <see cref="DateTimeOffset.MinValue"/> if the source DateTime was
/// <see cref="DateTime.MinValue"/>.
/// </summary>
/// <param name="dt">Source DateTime.</param>
/// <param name="offset">Offset</param>
public static DateTimeOffset ToDateTimeOffset(this DateTime dt, TimeSpan offset)
{
// adding negative offset to a min-datetime will throw, this is a
// sufficient catch. Note however that a DateTime of just a few hours can still throw
if (dt == DateTime.MinValue)
return DateTimeOffset.MinValue;
return new DateTimeOffset(dt.Ticks, offset);
}
public static DateTimeOffset ToDateTimeOffset(this DateTime dt, double offsetInHours = 0)
=> ToDateTimeOffset(dt, offsetInHours == 0 ? TimeSpan.Zero : TimeSpan.FromHours(offsetInHours));