Почему использование return в качестве последнего оператора функции считается неудачным?

Я читал документацию Rust и натолкнулся на следующий пример и выражение

Использование возврата в качестве последней строки функции работает, но считается плохим стилем:

fn foo(x: i32) -> i32 {
    if x < 5 { return x; }

    return x + 1;
}

Я знаю, что мог бы написать выше

fn foo(x: i32) -> i32 {
    if x < 5 { return x; }

    x + 1
}

но я более соблазнился написать первое, поскольку это более интуитивно понятно. Я понимаю, что возвращаемое значение функции должно использоваться в качестве выражения, чтобы позднее работало, но тогда почему бы не поощрять первое?

Ответ 1

Это просто.

У конвенций не должно быть особых оснований, они просто должны быть общепринятыми конвенциями. Как это бывает, у этого человека есть относительно веская причина - его короче, поскольку у вас нет return ; , Вы можете подумать, что return x + 1; более интуитивно понятен, но я не согласен сильно - это действительно решёт, и я чувствую настоятельную необходимость исправить это. Я говорю об этом как о том, кто до начала использования Rust никогда раньше не использовал язык, ориентированный на выражение. При написании Python, return x + 1 в этом месте, посмотрите правильно, при написании Rust это выглядит неправильно.

Теперь, как это бывает, этот код, вероятно, должен быть написан таким образом:

fn foo(x: i32) -> i32 {
    if x < 5 {
        x
    } else {
        x + 1
    }
}

Это подчеркивает ориентацию выражения языка.

Ответ 2

Скопировано из reddit: почему синтаксис операторов return явный?


Ответ от @pcwalton

Явный возврат действительно раздражает в замыканиях. Например, до появления функций стрелок ES6 в JavaScript была большая проблема

myArray.map(function(x) { return x * 2; })

является многословным, даже без ключевого слова function. Если у вас есть неявные возвраты где-то на вашем языке, вы также можете иметь их везде для согласованности. Тот факт, что он делает код менее многословным, является лишь дополнительным бонусом.

и из @mozilla_kmc

Rust - это язык, ориентированный на выражения. Блок имеет форму

{
    stmt;
    stmt;
    ...
    stmt;
    expr
}

Операторы являются (в основном) выражениями или привязками let, а конечное выражение неявно () если не указано. Значение всего блока является значением этого последнего выражения.

Это не только для функций. Ты можешь написать

let foo = if x { y } else { z };

так что if также занимает место оператора C ?: Каждый вид блока работает одинаково:

let result = unsafe {
    let y = mem::transmute(x);
    y.frob()
};

Таким образом, неявный возврат в конце функции является естественным следствием синтаксиса, ориентированного на выражения Rust. Улучшенная эргономика просто приятный бонус :)

Головоломка: return x само по себе является выражением - какова его ценность?

Ответ:

Это тип блока ().

Ответ 3

Clippy ворс дает следующее рациональны для needless_return ворса:

Удаление возврата и точки с запятой сделает код более ржавым.

Это, вероятно, так же хорошо, как и объективное обоснование, которое мы когда-либо получим.

Что касается интуиции; Я чувствую, что он сформирован нашими индивидуальными переживаниями и поэтому субъективен. Хотя Rust не является языком самого функционального программирования, многие люди, использующие и развивающие его, похоже, имеют сильный опыт в таких функциональных языках программирования, как Haskell, которые полностью основаны на выражениях. Влияние может сильно ощущаться во многих областях Rust (например, обработка ошибок). Таким образом, для них (и, честно говоря, я включил себя) использование выражения вместо выражения кажется более элегантным.