铁 rust 中的FizzBuzz函数

nzk0hqpo  于 2023-02-04  发布在  其他
关注(0)|答案(2)|浏览(134)

这是我的代码:

fn main() { 
  fn fizz_buzz<'a>(i: i32) -> &'a str { 

    if i % 15 == 0 { 
        "FizzBuzz"
    } else if i % 5 == 0 { 
        "Buzz"
    } else if i % 3 == 0 { 
        "Fizz"
    } else { 
        &i.to_string()
    }
  }

  for i in 1..101 { 
    println!("{}" , fizz_buzz(i));
  }
}

编译器给我这个错误:

error[E0515]: cannot return reference to temporary value
  --> src/main.rs:11:9
   |
11 |         &i.to_string()
   |         ^-------------
   |         ||
   |         |temporary value created here
   |         returns a reference to data owned by the current function

For more information about this error, try `rustc --explain E0515`.
error: could not compile `playground` due to previous error

我试过一辈子一成不变。

wfsdck30

wfsdck301#

你的函数将正确给予一个对字符串“FizzBuzz”、“Buzz”和“Fizz”的引用(它们的生存期是静态的,因为它们是在中编译的),但是&i.to_string()没有相同的属性,让我们详细看看生存期:
fizz_buzz被调用时,i被复制(因为i32实现了Copy特性)并被赋予它,但是在else代码块中,我们做了以下操作:
1.创建新拥有的String
1.返回对该String的引用
然而,String的生命周期只有fizz_buzz函数调用的时间!因为我们需要在该作用域之外使用它的引用,Rust调用了foul。
有几种方法可以使这种类型安全。你可以返回拥有的值而不是引用:

fn fizz_buzz(i: i32) -> String {
    if i % 15 == 0 { String::from("FizzBuzz") }
    else if i % 5 == 0 { String::from("Buzz") }
    else if i % 3 == 0 { String::from("Fizz") }
    else { i.to_string() }
}

尽管这最终会在堆上创建许多相同的对象(例如,考虑一下有多少个“Fizz“)
我更喜欢的另一个选项是让fizz_buzz返回一个Option〈&str〉,并让调用作用域处理fizz_buzz返回None的情况。

fn fizz_buzz(i: i32) -> Option<&'static str> {
    if i % 15 == 0 { Some("FizzBuzz") }
    else if i % 5 == 0 { Some("Buzz") }
    else if i % 3 == 0 { Some("Fizz") }
    else { None }
}

for i in 1..101 {
    match fizz_buzz(i) {
        Some(v) => println!("{}", v),
        None => println!("{}", i),
    }
}

正如@RobinZigmond在评论中指出的,您还可以返回一个枚举并为它实现Display。

use std::fmt::{self, Display};

enum FizzBuzz {
    FizzBuzz,
    Fizz,
    Buzz,
    Other(i32)
}

impl Display for FizzBuzz {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::FizzBuzz => write!(f, "{}", "FizzBuzz"),
            Self::Fizz => write!(f, "{}", "Fizz"),
            Self::Buzz => write!(f, "{}", "Buzz"),
            Self::Other(i) => write!(f, "{}", i.to_string())
        }
    }
}

fn fizz_buzz(i: i32) -> FizzBuzz {
    if i % 15 == 0 { FizzBuzz::FizzBuzz }
    else if i % 5 == 0 { FizzBuzz::Buzz }
    else if i % 3 == 0 { FizzBuzz::Fizz }
    else { FizzBuzz::Other(i) }
}

fn main() {
    for i in 1..101 {
        println!("{}", fizz_buzz(i));
    }
}
nxagd54h

nxagd54h2#

你试图返回一个只存在于堆栈帧中的值的引用,这个堆栈帧在你退出函数时会消失。

fn main() {
    fn fizz_buzz(i: i32) -> String {

        if i % 15 == 0 {
            "FizzBuzz".to_string()
        } else if i % 5 == 0 {
            "Buzz".to_string()
        } else if i % 3 == 0 {
            "Fizz".to_string()
        } else {
            i.to_string()
        }
    }

    for i in 1..101 {
        println!("{}" , fizz_buzz(i));
    }
}

关键的一点是,String是一个存在于 heap 上的字符串,而不是存在于 stack 上的字符串,创建动态字符串的唯一方法(例如,将i32强制转换为字符串时所做的)是将其放在堆栈上,因此,必须更改方法签名。
(不过,我更喜欢亚当·斯密的回答!它清楚地表明了鲁斯特的生命周期概念是如何影响这一点的。)

相关问题