是否可以不使用生命周期参数编写此程序?

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

Is it possible to write this program without using lifetime parameter?

问题

pub fn anagrams_for<'a>(word: &'a str, possible_anagrams: &'a [&'a str]) -> Vec<&'a str>
英文:

Is it possible to write this program without using the lifetime parameter in

pub fn anagrams_for&lt;&#39;a&gt;(word: &amp;&#39;a str, 
        possible_anagrams: &amp;&#39;a [&amp;&#39;a str]) -&gt; Vec&lt;&amp;&#39;a str&gt;

?


main.rs

pub fn is_anagram(one_word: &amp;str, other_word: &amp;str) -&gt; bool {
    if one_word.len() != other_word.len() {
        return false;
    }
    for ch in one_word.chars() {
        if other_word.find(ch) == None {
            return false;
        }
    }
    true
}

pub fn anagrams_for&lt;&#39;a&gt;(word: &amp;&#39;a str, possible_anagrams: &amp;&#39;a [&amp;&#39;a str]) -&gt; Vec&lt;&amp;&#39;a str&gt; {
    let mut return_list = Vec::new();
    for &amp;item_str in possible_anagrams.iter() {
        if is_anagram(word, item_str) {
            return_list.push(item_str);
        }
    }
    return_list
}

fn main() {
    let word = &quot;inlets&quot;;
    let inputs = [&quot;hello&quot;, &quot;world&quot;, &quot;listen&quot;, &quot;pants&quot;];
    println!(&quot;{:?}&quot;, anagrams_for(word, &amp;inputs));
}

答案1

得分: 1

Sort of. The program as written can use a 'static lifetime.

pub fn anagrams_for(word: &str, possible_anagrams: &[&'static str]) -> Vec<&'static str> {

However, this is overly restrictive. The correct way to write it is like this.

pub fn anagrams_for<'a>(word: &str, possible_anagrams: &[&'a str]) -> Vec<&'a str> {

This function can always be used in place of the first function.

It's important to understand that every reference in a function signature always has a lifetime. Much of the time, these are inferred, but there is always an equivalent function that assigns lifetimes to every reference. The previous function is the same as this.

pub fn anagrams_for<'a, 'b, 'c>(word: &'b str, possible_anagrams: &'c [&'a str]) -> Vec<&'a str> {
英文:

Sort of. The program as written can use a &#39;static lifetime.

pub fn anagrams_for(word: &amp;str, possible_anagrams: &amp;[&amp;&#39;static str]) -&gt; Vec&lt;&amp;&#39;static str&gt; {

However, this is overly restrictive. The correct way to write it is like this.

pub fn anagrams_for&lt;&#39;a&gt;(word: &amp;str, possible_anagrams: &amp;[&amp;&#39;a str]) -&gt; Vec&lt;&amp;&#39;a str&gt; {

This function can always be used in place of the first function.

It's important to understand that every reference in a function signature always has a lifetime. Much of the time, these are inferred, but there is always an equivalent function that assigns lifetimes to every reference. The previous function is the same as this.

pub fn anagrams_for&lt;&#39;a, &#39;b, &#39;c&gt;(word: &amp;&#39;b str, possible_anagrams: &amp;&#39;c [&amp;&#39;a str]) -&gt; Vec&lt;&amp;&#39;a str&gt; {

答案2

得分: 1

生命周期省略规则来看,这是不可能的:

> 输入位置中的每个省略的生命周期都变成了一个不同的生命周期参数。这是fn定义的当前行为。

要理解这一点,您可能需要查看生命周期位置

根据规则,您的函数定义将有3个不同的生命周期参数。

pub fn anagrams_for(word: &str, possible_anagrams: &[&str]) -> Vec<&str>

拥有3个不同的生命周期参数是可以的,但是Rust无法选择应该用于输出位置 -> Vec<&str> 的哪个参数。

需要使用输入位置中的一个生命周期(或者更小的生命周期)来用于输出位置(当然,它应该是与返回值相关的生命周期),除非您没有返回'static生命周期,尽管在这种情况下,您应该明确声明为Vec<&'static str>(这与所有权和借用以及悬垂指针相关)。

注意: 在这里,更小的 是指包含在从输入位置选择的生命周期中的生命周期。


还有一条规则可能需要检查:

> 如果存在多个输入生命周期位置,但其中一个是 &self&mut self,则self的生命周期将分配给所有省略的输出生命周期。

这意味着像这样的代码将适用于生命周期省略,但只能从 &self 返回某些内容,而不能从其他位置返回。

struct SomeStruct;
impl SomeStruct {
    pub fn anagrams_for(&self, word: &str, possible_anagrams: &[&str]) -> Vec<&str> { 
        //...
        //返回的值应该与`&self`相关
    }
}
英文:

It is not possible, from lifetime elision rules :

> Each elided lifetime in input position becomes a distinct lifetime parameter. This is the current behavior for fn definitions.

(To understand that you might want to check lifetime positions)

According to rules, your function's definition will have 3 distinct lifetime parameter.

pub fn anagrams_for(word: &amp;str, possible_anagrams: &amp;[&amp;str]) -&gt; Vec&lt;&amp;str&gt;

It is ok to have 3 distinct lifetime parameter but Rust is not able to choose which parameter should be used for the output position -&gt; Vec&lt;&amp;str&gt;.

One of the lifetime(or smaller) from input positions needs to be used on output position(of course it should be the lifetime that related with the returned value), unless you are not returning &#39;static lifetime, though you should explicitly declare that as Vec&lt;&amp;&#39;static str&gt; (this topic is related of ownership and borrowing, dangling pointers)

Note: By smaller I meant a lifetime that contained by the selected lifetime from input positions.


There is also one rule you might want to check

> If there are multiple input lifetime positions, but one of them is &self or &mut self, the lifetime of self is assigned to all elided output lifetimes.

This means code like this will work for lifetime elision, but you can only return something from the &amp;self, not from the others.

struct SomeStruct;
impl SomeStruct {
    pub fn anagrams_for(&amp;self, word: &amp;str, possible_anagrams: &amp;[&amp;str]) -&gt; Vec&lt;&amp;str&gt; { 
        //...
        //return value(s) should be related with `&amp;self`
    }
}

答案3

得分: 1

回答

你需要包括生命周期参数,因为在这里生命周期省略无法发生。编译器生成的错误包含了原因,即Rust无法确定返回值是从word还是possible_anagrams中借用的。

一个隐藏的问题

虽然你已经添加了生命周期以满足编译器的要求,但可能存在意外的副作用。考虑以下情况:

let inputs = ["hello", "world", "listen", "pants"];
let matches = {
    // 假装这是获取用户输入的操作。
    let word = String::from("inlets");
    anagrams_for(&word, &inputs)
};
println!("{matches:?}");

这段代码不会编译,因为根据函数签名,anagrams_for 的返回值从 word 借用,并且 word 的生命周期不够长。但实际上这并不重要,因为我们知道我们并没有从 word 借用。因此,让我们更新函数签名以解决这个问题:

pub fn anagrams_for<'a>(word: &str, possible_anagrams: &[&'a str]) -> Vec<&'a str> {
    let mut return_list = Vec::new();
    for &item_str in possible_anagrams.iter() {
        if is_anagram(word, item_str) {
            return_list.push(item_str);
        }
    }
    return_list
}

在这里,返回值的生命周期与possible_anagrams中的&str相同,这意味着它不再受限于测试单词的生命周期。

无关的说明:

anagrams_for的函数体也可以写成:

possible_anagrams
    .iter()
    .map(|ana| *ana)
    .filter(|ana| is_anagram(word, ana))
    .collect()
英文:

Answer

You do need to include the lifetime parameter because lifetime elision can’t take place here. The error that the compiler generates includes the reason, which is that Rust can’t tell whether the returned value is borrowed from word or possible_anagrams.

A Hidden Problem

While the way that you have added the lifetimes does appease the compiler, there’s likely an unintended side-effect. Consider:

let inputs = [&quot;hello&quot;, &quot;world&quot;, &quot;listen&quot;, &quot;pants&quot;];
let matches = {
    // Pretend this was getting user input.
    let word = String::from(&quot;inlets&quot;);
    anagrams_for(&amp;word, &amp;inputs)
};
println!(&quot;{matches:?}&quot;);

This won’t compile, because according to the function signature the return value of anagrams_for borrows from word, and word doesn’t live long enough. This shouldn’t matter though, because we know we aren’t borrowing from word. So let’s update the function signature to work:

pub fn anagrams_for&lt;&#39;a&gt;(word: &amp;str, possible_anagrams: &amp;[&amp;&#39;a str]) -&gt; Vec&lt;&amp;&#39;a str&gt; {
    let mut return_list = Vec::new();
    for &amp;item_str in possible_anagrams.iter() {
        if is_anagram(word, item_str) {
            return_list.push(item_str);
        }
    }
    return_list
}

Here the lifetime of the return value is the same as the &amp;str in possible_anagrams, which means it’s no longer bound to the lifetime of the test word.

Unrelated note:

The body of anagrams_for can also be written as:

possible_anagrams
    .iter()
    .map(|ana| *ana)
    .filter(|ana| is_anagram(word, ana))
    .collect()

huangapple
  • 本文由 发表于 2023年6月9日 12:45:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/76437270.html
匿名

发表评论

匿名网友

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

确定