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

huangapple go评论65阅读模式
英文:

Using a type definition to simplify a function signature

问题

Clippy正在发出以下警告:

警告:使用了非常复杂的类型。考虑将部分内容拆分为“类型”定义
   --> 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))> {
    |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = 帮助:更多信息请访问 https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity
    = 注意:默认情况下启用了`#[warn(clippy::type_complexity)]`

我同意这个警告。当我键入这段代码时,我不喜欢它,但似乎无法弄清楚在哪里以及如何放置type语句。我查阅了文档,遵循了Clippy提供的参考链接,进行了谷歌搜索,但似乎找不到有关使用type来简化函数签名或处理String参数上的生命周期的相关信息。定义一个新的结构来保存返回值将起作用,但除了简化函数定义之外,没有真正需要这样的结构。


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

英文:

Clippy is giving the following warning:

warning: very complex type used. Consider factoring parts into `type` definitions
   --&gt; src/regexp/mod.rs:845:56
    |
845 |     pub fn get_by_name&lt;&#39;b&gt;(&amp;&#39;b self, name: &amp;&#39;b str) -&gt; Vec&lt;(&amp;&#39;b String, (usize, usize), (usize, usize))&gt; {
    |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = 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

I agree with the warning. When I typed this code I didn't like it, but I can't seem to figure out where and how to put the type statement. I've looked in the book, followed the reference link clippy gave, and googled, and can't seem to find references to using type to simplify function signatures, or how to deal with the lifetime on the String parameter. Defining a new struct to hold the return value would work, but there isn't really any reason for such a structure besides simplifying the function definition.


Here's the code. You can see I fixed it by using the existing Report struct - it has a few extra fields that weren't in my design for the return, but the struct already exist, and it actually may be better to make the extra fields available. But thanks for the answer, it is something I should know whether or not it is used here.

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(&quot;&quot;) it is included but
    /// unnamed, otherwise it is recorded with the given name
    pub name: Option&lt;String&gt;,
    /// 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&lt;Report&gt;,
}

impl Report {
    /// Constructor: creates a new report from a successful Path
    pub fn new(root: &amp;crate::regexp::walk::Path, char_start: usize, byte_start: usize) -&gt; 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(&amp;self, indent: isize) {
        let name_str = { if let Some(name) = &amp;self.name { format!(&quot;&lt;{}&gt;&quot;, name) } else { &quot;&quot;.to_string() }};
        println!(&quot;{}\&quot;{}\&quot; char position [{}, {}] byte position [{}, {}] {}&quot;,
                 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, _\?\&lt;name\&gt;abc\)*_
    pub fn get_by_name&lt;&#39;b&gt;(&amp;&#39;b self, name: &amp;&#39;b str) -&gt; Vec&lt;&amp;Report&gt; {
        let mut v = Vec::&lt;&amp;Report&gt;::new();
        if let Some(n) = &amp;self.name {
            if n == name { v.push(self); }
        }
        for r in &amp;self.subreports {
            let mut x = r.get_by_name(name);
            v.append(&amp;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(&amp; self) -&gt; HashMap&lt;&amp;str, Vec&lt;&amp;Report&gt;&gt; {
        let hash = HashMap::new();
        self.get_named_internal(hash)
    }

    /// internal function that does the work for **get_named()**
    fn get_named_internal&lt;&#39;b&gt;(&amp;&#39;b self, mut hash: HashMap&lt;&amp;&#39;b str, Vec&lt;&amp;&#39;b Report&gt;&gt;) -&gt; HashMap&lt;&amp;&#39;b str, Vec&lt;&amp;Report&gt;&gt; {
        if let Some(name) = &amp;self.name {
            if let Some(mut_v) = hash.get_mut(&amp;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
    }
}



</details>


# 答案1
**得分**: 5

有几种简化方法。 其中一种是将整个类型取一个别名(选择一个合适描述的名称而不是 `Foo`):

```rust
type Foo<'a> = Vec<(&'a str, (usize, usize), (usize, usize))>;

然后你的返回类型是 Foo<'b>

如果这个元组类型经常出现,你可以将其分离出来:

type Foo<'a> = (&'a str, (usize, usize), (usize, usize));

然后你将返回 Vec<Foo<'b>>

很难在不看到你代码的其余部分的情况下提出替代方案。

我似乎无法弄清楚在何处以及如何放置类型声明

你可以将 type 声明放在任何可以放置其他类型声明的地方,比如 structenum 等。

英文:

There's a few ways you could simplify this. One would be to just alias the whole type (choosing a suitably-descriptive name instead of Foo):

type Foo&lt;&#39;a&gt; = Vec&lt;(&amp;&#39;a String, (usize, usize), (usize, usize))&gt;;

Then your return type is Foo&lt;&#39;b&gt;.

If this tuple type shows up a lot, you could factor that out instead:

type Foo&lt;&#39;a&gt; = (&amp;&#39;a String, (usize, usize), (usize, usize));

And then you would return Vec&lt;Foo&lt;&#39;b&gt;&gt;.

It's a bit hard to suggest alternatives without seeing the rest of your code.

> I can't seem to figure out where and how to put the type statement

You can put type declarations anywhere you can put other type declarations, like struct, enum, etc.

huangapple
  • 本文由 发表于 2023年4月4日 08:18:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/75924607.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定