Chinaunix首页 | 论坛 | 博客
  • 博客访问: 117407
  • 博文数量: 165
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1655
  • 用 户 组: 普通用户
  • 注册时间: 2022-09-26 14:37
文章分类

全部博文(165)

文章存档

2024年(2)

2023年(95)

2022年(68)

我的朋友

分类: 数据库开发技术

2022-10-08 13:56:32

{BANNED}最佳近在用rust 写一个redis的数据校验工具。[redis-rs](
)中具备 redis::ConnectionLike trait,借助它可以较好的来抽象校验过程。在开发中,不免要定义struct 中的某些元素为 trait object,从而带来一些rust语言中的生命周期问题。

首先来定义一个 base trait,该 trait 中只包含一个函数,返回String类型。

```rust pub trait Base { fn say(&self) -> String;
}
```

接下来,定义两个实现了 Base trait 的 struct AFromBase 和 BFromBase

```Rust pub struct AFromBase {
    content: String,
} impl Base for AFromBase { fn say(&self) -> String { self.content.clone()
    }
} pub struct BFromBase {
    text: String,
} impl Base for BFromBase { fn say(&self) -> String { self.text.clone()
    }
}
```

接下来,定义一个struct 包含两个 Base trait 的 trait object ,然后实现一个函数是 say 函数输出的字符串的拼接结果.

按照其他没有生命周期语言的编写习惯,直觉上这么写

```rust pub struct AddTowBase {
    a: &mut dyn Base,
    b: &mut dyn Base,
} impl AddTowBase { fn add(&self) -> String { let result = self.a.say() + &self.b.say();
        result
    }
}
```


{BANNED}最佳后,搞个main函数验证一下。

完整代码如下:

```rust pub trait Base { fn say(&self) -> String;
} pub struct AFromBase {
    content: String,
} impl Base for AFromBase { fn say(&self) -> String { self.content.clone()
    }
} pub struct BFromBase {
    text: String,
} impl Base for BFromBase { fn say(&self) -> String { self.text.clone()
    }
} pub struct AddTowBase {
    a: &mut dyn Base,
    b: &mut dyn Base,
} impl<'a> AddTowBase<'a> { fn add(&self) -> String { let result = self.a.say() + &self.b.say();
        result
    }
} fn main() { let mut a = AFromBase {
        content: "baseA".to_string(),
    }; let mut b = BFromBase {
        text: "baseB".to_string(),
    }; let addtow = AddTowBase {
        a: &mut a,
        b: &mut b,
    }; let r = addtow.add(); println!("{}", r);
}
```

很遗憾,以上代码是不能编译通过的,编译时报如下错误:

 ```shell
error[E0106]: missing lifetime specifier
  --> examples/lifetimeinstruct.rs:26:8 | 26 |     a: &mut dyn Base,
   |        ^ expected named lifetime parameter
   |
help: consider introducing a named lifetime parameter
   | 25 ~ pub struct AddTowBase<'a> { 26 ~     a: &'a mut dyn Base,
   |


error[E0106]: missing lifetime specifier
  --> examples/lifetimeinstruct.rs:27:8 | 27 |     b: &mut dyn Base,
   |        ^ expected named lifetime parameter
   |
help: consider introducing a named lifetime parameter
   | 25 ~ pub struct AddTowBase<'a> { 26 |     a: &mut dyn Base, 27 ~     b: &'a mut dyn Base,
   |


For more information about this error, try `rustc --explain E0106`.
error: could not compile `wenpan-rust` due to 2 previous errors
```


编译器给出的提示很明确,要在 trait object 上添加生命周期参数,确保 struct 和他的 trait object 元素在同一生命周期,避免悬垂指针。

我们按照编译器的提示修改代码:

```rust pub struct AddTowBase<'a> {
    a: &'a mut dyn Base,
    b: &'a mut dyn Base,
} impl<'a> AddTowBase<'a> { fn add(self) -> String { let result = self.a.say() + &self.b.say();
        result
    }
}
```


代码顺利通过编译。

rust 的生命周期保证了内存的安全性,同时也增加了开发者的心智负担。是在上线之前多费心思写代码,还是在上线以后忙忙活活查问题,这是个 trade off 问题。俗话讲:"背着抱着,一样沉"。我本人还是倾向于把问题控制在上线之前,少折腾用户。

本期咱们先聊到这儿,下期见。

阅读(212) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~