Есть ли способ использовать постфиксную нотацию для вызова функции в Rust без определения новой черты? - PullRequest
1 голос
/ 02 июня 2019

Возможно, моя терминология неверна, но есть ли способ использовать постфиксную нотацию для вызова функции в Rust без определения новой черты? По сути, у меня есть вектор &str, и я хотел бы преобразовать их в строку с обозначением myvec.as_string(). В настоящее время я могу сделать это с кодом

trait Foo {                
    fn as_string(&self) -> String;
}   

impl Foo for Vec<&str> {  
    fn as_string(&self) -> String {
        let mut mystr = self
            .iter()
            .fold(String::new(),|sum,s| format!("{}{}:", sum, s));
        mystr.pop();
        mystr
    }
}

fn main() {
    let my_vec = vec!["bar", "buz", "baz"];
    use crate::Foo;       
    println!("{}", my_vec.as_string());
}

Тем не менее, чтобы сделать эту работу, мне нужно было определить черту под названием Foo, которая меня не особо интересует, и эту черту нужно было открыть с помощью use crate::Foo до вызова as_string , Есть ли лучший способ сделать это? И, чтобы быть ясным, я хотел бы избежать обозначения as_string(myvec), если это возможно, потому что запись постфикса была удобна для объединения команд.

1 Ответ

5 голосов
/ 02 июня 2019

Это обычная модель!

Если вы хотите добавить методы к типу, который определен в другом ящике, официальный способ сделать это - определить черту и реализовать ее для этого типа. Если тип из другого ящика, то это способ только .

Повсеместным примером этого является ящик itertools, который использует черту для добавления полезных методов в каждую существующую реализацию std::iter::Iterator.

Itertools работает так же, как вы описываете. Существует черта, которая объявляет ряд методов:

pub trait Itertools : Iterator {
    fn interleave<J>(self, other: J) -> Interleave<Self, J::IntoIter>
        where J: IntoIterator<Item = Self::Item>,
              Self: Sized
    {
        interleave(self, other)
    }

    // etc...
}

Определено для всех Iterator с:

impl<T: ?Sized> Itertools for T where T: Iterator { }

И всякий раз, когда вы хотите использовать эти дополнительные методы, вы импортируете его:

use itertools::Itertools;

let it = (1..7).interleave(vec![-1, -2]);
itertools::assert_equal(it, vec![1, -1, 2, -2, 3, 4, 5, 6]);
...