_ => что означает это подчеркивание в лямбда-выражениях?


111

Что означает лямбда-выражение _=> expr?

Какова цель использования _лямбды?

Пример:

int count = 0;
list.ForEach(_ => count += 1);

8
Привет и добро пожаловать в StackOverflow. Я позволил себе немного отредактировать ваш вопрос, чтобы увеличить ваши шансы на получение полезных ответов, надеюсь, вы не против.
Лассе В. Карлсен

Следует отметить , что, предполагая listэто IEnumerable<T>, они могут (и должны) только что использовалиsum = list.Count();
BlueRaja - Дэнни Pflughoeft

Я предполагаю, что это можно использовать для предотвращения «засорения» области видимости новым именем переменной, которое может быть использовано где-то еще, что может вызвать конфликт.
Тим Шмелтер

Ответы:


84

Это соглашение используется, когда вам не нужен параметр.


3
Это чаще встречается в Haskell и других функциональных языках. Я думаю, что это откуда.
Гейб Мутхарт

10
В Haskell, ML, Scala и других _это подстановочный знак при сопоставлении с образцом. Это в основном означает: «Мне все равно, я всегда хочу, чтобы это совпадало». Это «мне все равно» затем переносится, когда дело доходит до наименования вещей, которые вам не нужны, и оттуда оно перетекает на другие языки программирования. Он, например, также используется в Ruby для обозначения того же значения, что и в этом примере, хотя _в Ruby не имеет абсолютно никакого особого значения.
Jörg W Mittag

@ JörgWMittag Верно в мае 2010 г., но не по состоянию на июнь 2010 г. Отличное время! :) stackoverflow.com/q/6397078/38765
Эндрю Гримм,

38

Это имя параметра, хотя и бесполезное, но оно обычно используется (по некоторым соглашениям), когда вам нужно указать, что выражение имеет параметр, чтобы код компилировался, но вам все равно об этом, так что вы просто проигнорируете это.

Он в основном использует синтаксис того, что представляет собой законный идентификатор в C #, и поскольку идентификатор может начинаться с подчеркивания и не содержать ничего другого, это просто имя параметра.

Вы могли бы легко написать:

var _ = 10;

1
Можем ли мы использовать () вместо _?
amesh 03

2
Вы пробовали это использовать?
Лассе В. Карлсен

Да, я использовал его, когда создавал поток с использованием лямбда-выражения. Thread t= new Thread(()=>doSomething(x,y)); t.start();
amesh 03

Я предполагаю, что использование _ передает каждую переменную коллекции в лямбда-выражение, даже если оно не используется. Но когда мы используем (), этого может и не произойти. Я имею в виду параметр меньше лямбды.
amesh 03

Вам нужно попробовать это с помощью вызова метода ForEach. В конструкторе Thread есть перегрузка, которая принимает делегат, не принимающий никаких параметров. Попробуйте вызвать такой метод, как этот ForEach, который вместо этого принимает делегат, который принимает параметр.
Лассе В. Карлсен


10

Поскольку выражение lamda в основном используется в коротком анонимном коде, поэтому имя переменной иногда не требуется, даже если они не используют переменную в блоке кода, поэтому они просто дают _ для краткого соглашения


7

Я также поддерживаю использование _ => _.method()однострочных лямбда-выражений с вызовом метода, поскольку это снижает когнитивный вес инструкции. Особенно при использовании обобщений письмо x => x.method()просто добавляет долю секунды к вопросу «Что это за« x »? Это координата в пространстве?».

Рассмотрим следующий случай:

Initialize<Client> ( _=>_.Init() );

Используемый с вызовом Generics, подчеркивание в этом случае работает как «символ обхода». Он избегает избыточности, определяя, что тип аргумента очевиден и может быть получен из использования - точно так же, как когда вы используете 'var' для предотвращения повторения объявления типа. Написание client=>client.Init()здесь просто сделало бы инструкцию длиннее, не добавляя к ней никакого смысла.

Очевидно, это не относится к параметрам, передаваемым в метод, который следует назвать описательно. Например.:Do( id=>Log(id) );

Использование одного параметра подчеркивания для вызовов методов вряд ли оправдано при использовании блока кода вместо однострочного, поскольку лямбда-идентификатор отключается от определения своего универсального типа. Обычно, когда один и тот же идентификатор должен использоваться повторно, дайте ему описательное имя.

Суть в том, что многословие оправдано только для устранения неоднозначности, особенно для лямбда-выражений, которые были созданы, в первую очередь, для упрощения создания анонимных делегатов. В любом случае следует руководствоваться здравым смыслом, сбалансировав разборчивость и лаконичность. Если символ является лишь «приманкой» к реальной функциональности, односимвольные идентификаторы вполне подойдут. Так обстоит дело с циклами For и буквами «i» и «j» в качестве индексаторов.


2
+1 за такой подход! Я был единственным, кто использовал символы подчеркивания в лямбдах, чтобы «снизить когнитивный вес», а не для того, чтобы показать, что этот параметр не используется. С подчеркиванием легче читать, особенно если много цепочек и вы можете сразу определить тип, как это часто бывает с запросами LINQ!
Варвара Калинина

3
Do(id => Log(id))лучше сокращать как Do(Log).
Алуан Хаддад
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.