使用类型定义来简化函数签名

rus*_*ell 1 types rust rust-clippy

Clippy 发出以下警告:

warning: very complex type used. Consider factoring parts into `type` definitions
   --> src/regexp/mod.rs:845:56
    |
845 |     pub fn get_by_name<'b>(&'b self, name: &'b str) -> Vec<(&'b String, (usize, usize), (usize, usize))> {
    |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity
    = note: `#[warn(clippy::type_complexity)]` on by default
Run Code Online (Sandbox Code Playgroud)

我同意这个警告。当我输入这段代码时,我不喜欢它,但我似乎不知道在哪里以及如何放置该type语句。我查过这本书,按照 Clippy 给出的参考链接进行搜索,似乎无法找到有关使用来type简化函数签名或如何处理参数生命周期的参考String。定义一个新的结构来保存返回值是可行的,但除了简化函数定义之外,实际上没有任何理由需要这样的结构。


这是代码。您可以看到我通过使用现有的 Report 结构来修复它 - 它有一些额外的字段不在我的返回设计中,但该结构已经存在,并且实际上使额外的字段可用可能会更好。但谢谢你的回答,我应该知道这里是否使用它。

pub struct Report {
    /// The string found matching the RE pattern
    pub found: String,
    /// The position in chars of the string. This cannot be used for slices, except for ASCII chars. To get a slice use **pos**
    pub pos: (usize, usize),
    /// The position in bytes of the string: that is, found[pos.0..pos.1] is a valid unicode substring containing the match
    pub bytes: (usize, usize),
    /// The name of the field: if None then the field should not be included in the Report tree, if Some("") it is included but
    /// unnamed, otherwise it is recorded with the given name
    pub name: Option<String>,
    /// Array of child Report structs, only non-empty for And and Or nodes. OrNodes will have only a single child node, AndNodes can have many.
    pub subreports: Vec<Report>,
}

impl Report {
    /// Constructor: creates a new report from a successful Path
    pub fn new(root: &crate::regexp::walk::Path, char_start: usize, byte_start: usize) -> Report {
        let (reports, _char_end)  = root.gather_reports(char_start, byte_start);
        reports[0].clone()
    }
    
    /// Pretty-prints a report with indentation to help make it easier to read
    pub fn display(&self, indent: isize) {
        let name_str = { if let Some(name) = &self.name { format!("<{}>", name) } else { "".to_string() }};
        println!("{}\"{}\" char position [{}, {}] byte position [{}, {}] {}",
                 pad(indent), self.found, self.pos.0, self.pos.1, self.bytes.0, self.bytes.1, name_str);
        self.subreports.iter().for_each(move |r| r.display(indent + 1));
    }

    /// Gets **Report** nodes representing matches for named Nodes. The return is a *Vec* because named matches can occur multiple
    /// times - for example, _\?\<name\>abc\)*_
    pub fn get_by_name<'b>(&'b self, name: &'b str) -> Vec<&Report> {
        let mut v = Vec::<&Report>::new();
        if let Some(n) = &self.name {
            if n == name { v.push(self); }
        }
        for r in &self.subreports {
            let mut x = r.get_by_name(name);
            v.append(&mut x);
        }
        v
    }

    /// Gets a hash of  **Report** nodes grouped by name. This just sets things up and calls **get_named_internal()** to do the work
    pub fn get_named(& self) -> HashMap<&str, Vec<&Report>> {
        let hash = HashMap::new();
        self.get_named_internal(hash)
    }

    /// internal function that does the work for **get_named()**
    fn get_named_internal<'b>(&'b self, mut hash: HashMap<&'b str, Vec<&'b Report>>) -> HashMap<&'b str, Vec<&Report>> {
        if let Some(name) = &self.name {
            if let Some(mut_v) = hash.get_mut(&name.as_str()) {
                mut_v.push(self);
            } else {
                hash.insert(name.as_str(), vec![self]);
            }
            for r in self.subreports.iter() {
                hash = r.get_named_internal(hash);
            }
        }
        hash
    }
}

Run Code Online (Sandbox Code Playgroud)

cdh*_*wie 5

有几种方法可以简化这个过程。一种方法是为整个类型起别名(选择一个适当的描述性名称而不是Foo):

type Foo<'a> = Vec<(&'a String, (usize, usize), (usize, usize))>;
Run Code Online (Sandbox Code Playgroud)

那么你的返回类型是Foo<'b>.

如果此元组类型出现很多,您可以将其排除:

type Foo<'a> = (&'a String, (usize, usize), (usize, usize));
Run Code Online (Sandbox Code Playgroud)

然后你就会回来Vec<Foo<'b>>

在没有看到其余代码的情况下很难提出替代方案。

我似乎不知道在哪里以及如何放置类型声明

您可以将type声明放在可以放置其他类型声明的任何位置,例如structenum等。