Спасибо всем за полезные взаимодействия.Все изложенное в предыдущем ответе точно правильно.И есть более широкая картина, когда я изучаю Rust.
Исходя из Haskell (с обучением C много лет назад), я наткнулся на подход цепочки методов OO, который использует указатель для цепочки между вызовами методов;нет необходимости в чистых функциях (то есть, что я делал с let mut result = ...
, который затем использовался / требовался для изменения значения Vec
с использованием push
в result.push(...)
).Я считаю, что более общее наблюдение заключается в том, что в ОО "aok" возвращено unit
, потому что цепочка методов не требует возвращаемого значения.
Пользовательский код ниже определяет push
как черту;он использует те же входные данные, что и «OO» push
, но возвращает обновленный self
.Возможно, только в качестве дополнительного комментария, это делает функцию чистой (вывод зависит от ввода), но на практике означает, что push
, определенный как черта, позволяет составлять функции FP, которые я ожидал, была нормой (достаточно справедливо, я думалсначала учитывая, сколько Rust позаимствовал у Haskell).
То, что я пытался выполнить, и в основе вопроса заложено решение для кода, предложенное @Stargateur, @ E_net4 и @Shepmaster.Только самые маленькие правки следующие: (см. детская площадка )
pub fn build_proverb(list: &[&str]) -> String {
if list.is_empty() {
return String::new();
}
list.windows(2)
.map(|d| format!("For want of a {} the {} was lost.", d[0], d[1]))
.collect::<Vec<_>>()
.push(format!("And all for the want of a {}.", list[0]))
.join("\n")
}
Решение требует, чтобы я определил push
как черту, которая возвращает self
, тип Vec
в этом случае.
trait MyPush<T> {
fn push(self, x: T) -> Vec<T>;
}
impl<T> MyPush<T> for Vec<T> {
fn push(mut self, x: T) -> Vec<T> {
Vec::push(&mut self, x);
self
}
}
Последнее замечание: при рассмотрении многих признаков Rust я не смог найти функцию признака, которая возвращает ()
(по модулю, например, Write
, которая возвращает Result ()
).
Это контрастирует с тем, что я научился ожидать от struct
и enum
methods
.Обе черты и методы OO имеют доступ к self
и, таким образом, каждый из них описан как «методы», но, похоже, есть существенное отличие, на которое следует обратить внимание: методы OO используют ссылку, чтобы разрешить последовательное изменение self
, черты FP (если хотите) использует композицию функций, которая полагается на использование «чистых», изменяющих состояние функций для достижения того же (:: (self, newValue) -> self
).
Возможно, в качестве отступления, когда Haskell достигает ссылочной прозрачности в этой ситуации путем создания новой копии (по модулю закулисных оптимизаций), Rust, кажется, выполняет нечто подобное в пользовательском коде черты, управляя владением (передается вФункция trait, и возвращаемая, возвращая self
).
Завершающий кусок головоломки «Функции составления»: чтобы композиция работала, вывод одной функции должен иметь тип, необходимый для вводаследующая функция.join
работал как при передаче ему значения, так и при передаче ему ссылки (верно для типов, которые реализуют IntoIterator
).Так что join
, кажется, обладает способностью работать как в цепочках методов, так и в стилях композиции функций программирования.
Является ли это различие между ОО-методами, которые не полагаются на возвращаемое значение, и признаками, как правило, справедливыми в Rust?Вроде бы дело "здесь и там".Например, в отличие от push
, где линия ясна, join
, похоже, находится на пути к тому, чтобы стать частью стандартной библиотеки, определенной как метод для SliceConcatExt
и функция черты для SliceConcatExt
( см. Руководство по ржавчине и обсуждение проблемы ржавчины ).Следующий вопрос, будет ли унификация подходов в стандартной библиотеке соответствовать философии дизайна Rust?(платите только за то, что вы используете, безопасно, эффективно, выразительно и приятно)