< 返回版块

overheat 发表于 2021-06-16 00:03

Hi, 我想用闭包实现两个字符串字面量的合并,并且返回&str类型,代码如下:

    let mut s = String::new();
    let mut format_as_str = |a, b| {
        s = format!("{}/{}", a, b);
        s.as_str()
    };

但是,最后面那句s.as_str()报错:

captured variable cannot escape `FnMut` closure body

请教,为啥~

评论区

写评论
作者 overheat 2021-06-16 06:33

大神! 学习了!

--
👇
苦瓜小仔: 当然,如果你让编译器给你推断闭包返回值类型也不是不可以, 大部分情况下的确不需要自己标注返回值类型。

但是返回来自函数内部数据的 引用 ,这个操作本来就容易造成不安全的悬垂引用。 所以编译器只会基于最安全的方式给你推断一个有所有权的 String 类型。

fn main() {
    let concat_str = |a: &'_ str, b: &'_ str| { // concat_str: |…| -> String
        let s = format!("{}/{}", a, b); // s: String
        s
    };

    let s = concat_str("hello", "world"); // s: String
    println!("{:?}", s);
}

但是基于你的需求——返回 &str ——“绕开”编译器的规则,那么就只有走“弯路”了。

苦瓜小仔 2021-06-16 01:25

当然,如果你让编译器给你推断闭包返回值类型也不是不可以, 大部分情况下的确不需要自己标注返回值类型。

但是返回来自函数内部数据的 引用 ,这个操作本来就容易造成不安全的悬垂引用。 所以编译器只会基于最安全的方式给你推断一个有所有权的 String 类型。

fn main() {
    let concat_str = |a: &'_ str, b: &'_ str| { // concat_str: |…| -> String
        let s = format!("{}/{}", a, b); // s: String
        s
    };

    let s = concat_str("hello", "world"); // s: String
    println!("{:?}", s);
}

但是基于你的需求——返回 &str ——“绕开”编译器的规则,那么就只有走“弯路”了。

苦瓜小仔 2021-06-16 01:01

不明白你这里用闭包的意义在哪? 因为闭包通常用于捕获环境变量或者简短的函数体。

如果你一开始写不出闭包,那么就从简单的函数开始。 弄清楚函数签名的含义和所涉及的类型。

无法理解你为什么要在外面定义一个没什么用的 s , 以及你这个闭包的写法怎么看都有问题。

use std::borrow::Cow;

fn main() {    let s = concat("hello", "world"); // s: Cow<str>
    println!("{:?}", s);

    let concat_str = |a: &'_ str, b: &'_ str| -> Cow<'_, str> { 
        let s = format!("{}/{}", a, b); // s: String
        s.into()
    };

    let s = concat_str("hello", "world"); // s: Cow<str>
    println!("{:?}", s);
}

fn concat<'a>(a: &'a str, b: &'a str) -> Cow<'a, str> {
    let s = format!("{}/{}", a, b); // s: String
    s.into()
}

参考:

多补补基础知识吧。

1 共 3 条评论, 1 页