不同的字符串生命周期和丢弃

问题描述 投票:0回答:1

考虑这个函数,它从具有相同生命周期的两个切片中返回最长的字符串切片。

fn get_longest<'a>(s1: &'a str, s2: &'a str) -> &'a str {
    if s1.len() > s2.len() {
        s1
    } else {
        s2
    }
}

现在考虑这个测试函数,它应该失败,因为参数具有不同的生命周期。

#[test]
fn with_different_lifetimes() {
    let s1 = "very long string";
    let s2 = "tiny".to_string();
    let should_be_s1 = get_longest(s1, &s2);
    drop(s2);
    assert_eq!(should_be_s1, "very long string");
}

这是测试函数正确产生的错误。

error[E0505]: cannot move out of `s2` because it is borrowed
let s2 = "tiny".to_string();
    -- binding `s2` declared here
let should_be_s1 = get_longest(s1, &s2);
                                   --- borrow of `s2` occurs here
drop(s2);
     ^^ move out of `s2` occurs here
assert_eq!(should_be_s1, "very long string");
-------------------------------------------- borrow later used here

help: consider cloning the value if the performance cost is acceptable

let should_be_s1 = get_longest(s1, &s2);
let should_be_s1 = get_longest(s1, s2.clone());

现在假设我无权访问测试函数,因此无法像编译器建议的那样更改它,因此为了使其通过,我将

get_longest
的返回类型更改为
String

fn get_longest(s1: &str, s2: &str) -> String {
    if s1.len() > s2.len() {
        s1.to_owned()
    } else {
        s2.to_owned()
    }
}

如何更改原始函数

get_longest
,以便测试函数
with_different_lifetimes
通过,并且仍然返回对字符串切片的引用而不是新的
String

换句话说,这个比较引用的测试函数也应该通过。

#[test]
fn equal_reference() {
    let s1 = "tiny";
    let s2 = "very long string".to_string();
    let should_be_ref_s2 = get_longest(s1, &s2);
    assert_eq!(should_be_ref_s2, &s2);
}

这可能吗?

rust lifetime
1个回答
0
投票

第二次测试的唯一问题是您无法比较

String
&String
。比较运算符通常不在拥有的类型和引用之间实现,因为运算符已经通过引用获取其操作数。不过,这样做也没有什么坏处。

您无法制作

impl PartialEq<&String> for String
,但您可以制作与
&str
&String
相当的包装类型。这将使两个测试都编译并通过。

#[derive(Debug)]
pub struct StringCmp(pub String);

impl PartialEq<&String> for StringCmp {
    fn eq(&self, other: &&String) -> bool {
        self.0.eq(*other)
    }
}

impl PartialEq<&str> for StringCmp {
    fn eq(&self, other: &&str) -> bool {
        self.0.eq(*other)
    }
}

pub fn get_longest(s1: &str, s2: &str) -> StringCmp {
    if s1.len() > s2.len() {
        StringCmp(s1.to_owned())
    } else {
        StringCmp(s2.to_owned())
    }
}

游乐场

© www.soinside.com 2019 - 2024. All rights reserved.