【问题标题】:Rust lazy_static! macro with a post-processed string?生锈懒惰的静态!带有后处理字符串的宏?
【发布时间】:2021-02-14 14:02:03
【问题描述】:

我正在尝试使用递归公用表表达式(大约 80 行 SELECT 语句)集成一个相当复杂的 SQL 查询。有两种不同的查询可以作为递归的种子。我不想在我的代码中嵌入两个不同的 80 行 SQL 语句,相差一行,谢谢,但我也想避免在每次使用时重新计算这些表达式,所以 lazy_static!include_str! 看起来像要走的路。

lazy_static! {
    static ref select_kasten_by_title_sql: &'static str = str::replace(
        include_str!("sql/select_kasten_by_parameter.sql"),
        "QUERYPARAMETER",
        "zettlen.title"
    )
    .as_str();
}

除了我不断得到:

5 |        static ref select_kasten_by_title_sql: &'static str = str::replace(
   |   ___________________________________________________________^
   |  |___________________________________________________________|
   | ||
26 | ||         include_str!("sql/select_kasten_by_parameter.sql"),
27 | ||         "QUERYPARAMETER",
28 | ||         "zettlen.title").as_str();
   | ||________________________-________^ returns a value referencing data owned by the current function
   | |_________________________|
   |                            temporary value created here

这让我很困惑,因为我无法确定它指的是什么功能。我知道有一个临时值,但它的生命周期应该是这个表达式的持续时间,不应该,一旦它被设置为静态 str,就是这样,对吧?

【问题讨论】:

  • 根据lazy_static 的文档,初始化表达式在第一次取消引用静态时运行。因此,所引用的函数是Deref::deref 的实现。

标签: rust lifetime


【解决方案1】:

replace 创建一个新的owned String,它的生命周期与周围的范围一样长,因此as_str 返回的切片具有该生命周期。但是您随后尝试将其分配给 &'static str 变量。

您可以通过将静态变量的类型改为String 来修复它。

lazy_static! {
    static ref select_kasten_by_title_sql: String = str::replace(
        include_str!("sql/select_kasten_by_parameter.sql"),
        "QUERYPARAMETER",
        "zettlen.title"
    );
}

【讨论】:

    【解决方案2】:

    拆分变量更容易可视化:

    lazy_static! {
      static ref select_kasten_by_title_sql: &'static str = {
        let tmp = str::replace(
          include_str!("sql/select_kasten_by_parameter.sql"),
          "QUERYPARAMETER",
          "zettlen.title",
        );
        tmp.as_str()
      };
    }
    

    tmp 是一个由块作用域拥有的局部变量。您正在尝试返回对 tmp 的引用 - 您正在尝试返回引用当前范围拥有的数据的值。这是不可能的,编译器会告诉你:

    error[E0515]: cannot return value referencing local variable `tmp`
      --> src/main.rs:11:5
       |
    11 |     tmp.as_str()
       |     ---^^^^^^^^^
       |     |
       |     returns a value referencing data owned by the current function
       |     `tmp` is borrowed here
    

    一个简单的解决方法是直接返回String,而不是对其的引用:

    lazy_static! {
      static ref select_kasten_by_title_sql: String = str::replace(
        include_str!("sql/select_kasten_by_parameter.sql"),
        "QUERYPARAMETER",
        "zettlen.title"
      );
    }
    

    如果你真的非常想返回&'static str,你可以使用Box::leak。我不建议您这样做,因为它比 String 没有任何好处,但它是一种选择:

    lazy_static! {
      static ref T: &'static str = {
        let tmp = str::replace(
          include_str!("sql/select_kasten_by_parameter.sql"),
          "QUERYPARAMETER",
          "zettlen.title",
        );
        Box::leak(tmp.into_boxed_str())
      };
    }
    ``
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-18
      • 2014-10-01
      • 2012-07-08
      • 2018-08-07
      相关资源
      最近更新 更多