rust - Rust:重构后结构的可见性现在公开;无法将 main 添加到 pub(在 crate::main 中)
问题描述
我对 rust 比较陌生,所以以下也可能是对一个概念的误解:我从基本项目模板中获取了 ggez 基本项目模板,如下所示:
use ggez::{graphics, Context, ContextBuilder, GameResult};
use ggez::event::{self, EventHandler};
fn main() {
// Make a Context.
let (mut ctx, mut event_loop) = ContextBuilder::new("my_game", "Cool Game Author")
.build()
.expect("aieee, could not create ggez context!");
// Create an instance of your event handler.
// Usually, you should provide it with the Context object to
// use when setting your game up.
let mut my_game = MyGame::new(&mut ctx);
// Run!
match event::run(&mut ctx, &mut event_loop, &mut my_game) {
Ok(_) => println!("Exited cleanly."),
Err(e) => println!("Error occured: {}", e)
}
}
struct MyGame {
// Your state here...
}
impl MyGame {
pub fn new(_ctx: &mut Context) -> MyGame {
// Load/create resources such as images here.
MyGame {
// ...
}
}
}
impl EventHandler for MyGame {
fn update(&mut self, _ctx: &mut Context) -> GameResult<()> {
// Update code here...
Ok(())
}
fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
graphics::clear(ctx, graphics::WHITE);
// Draw code here...
graphics::present(ctx)
}
}
并将其重构为两个文件main.rs
,game.rs
第一个文件只包含main()
函数,其他所有文件都放入game.rs
.
将导入更改main.rs
为
mod game;
use game::MyGame;
use ggez::{graphics, Context, ContextBuilder, GameResult};
use ggez::event::{self, EventHandler};
并将其添加到game.rs
use ggez::event::EventHandler;
use ggez::{Context, GameResult, graphics};
MyGame
只要我公开,一切正常。
然而,现在重构正在发生巨大的变化,因为 MyGame 之前是私有的。我尝试了几种pub (in infinite_runner::main)
类似的方法,crate::main
但没有一个被各种错误消息接受。
现在我的问题是,有没有办法在不暴露MyGame
给main.rs
其他人的情况下暴露它?似乎 main 不是一个有效的目标。
解决方案
通过重申 rust 文档,我设法弄清楚了。虽然回答我自己的问题感觉有点可疑,但实际上可能对其他人有帮助:
TLDR;我们希望 main 函数内的代码能够访问 MyGame,但外部的任何其他模块都拒绝访问。
可以通过将代码分解为game.rs
:否。
是否可以做到:是的。
以下是原因和方法:
来自 rust 文档Visibility and Privacy:
由于项目是公共的或私有的,Rust 允许在两种情况下访问项目:
- 如果一个项目是公共的,那么如果您可以从 m 访问该项目的所有父模块,则可以从某个模块 m 外部访问它。您还可以通过再导出来命名该项目。见下文。
- 如果一个项目是私有的,它可以被当前模块及其后代访问。
这意味着我不能横向考虑并期望同时横向限制。由于main.rs
它位于顶层,因此与任何其他模块一样,整个 crate 都可以访问同一级别的任何公共内容,因为每个模块都可以访问顶层的父级。因此,将同一级别重构为文件(模块)的答案是:否。
附带说明一下,如果我将代码分解到一个名为的文件中,lib.rs
那么唯一的区别就是路径,因为lib.rs
在顶层隐含的只是crate
路径,而在一个名为game.rs
路径的文件中是crate::game
.
但是可以通过垂直分解来完成与单个文件相同的行为。我们创建一个名为的目录game
并在该目录中移动game.rs
,并将 pub 关键字添加到 MyGame: pub struct MyGame
。与 python__init__.py
文件类似,rust 需要一个文件mod.rs
来使目录成为模块。在我们的例子中mod.rs
,你声明了你在里面的文件mod game
。现在我们可以通过 path 来处理 MyGame crate::game::game::MyGame
,但是由于game.rs
声明为私有,因此对 MyGame 的访问是密封的,因为路径的所有元素都必须是公共的。但是,由于 MyGame 被声明为 public,因此同一级别的任何模块都可以访问它。我们无法将其移动main.rs
到游戏目录中,但我们可以将其中的代码分解到另一个函数中。让我们称之为init
因为缺乏幻想。init.rs
我们将 init 函数放在游戏目录中的一个名为的文件中,并在其中声明它为 public,如下所示mod.rs
:pub mod init
现在我们可以调用game::init::init()
,因为它是公开的,但不是game::game::MyGame
. 但是,Init 可以访问MyGame
.
最终结构如下所示:
src
|---main.rs
|---game
|---mod.rs
|---game.rs
|---init.rs
main.rs:
mod game;
use game::init;
fn main() {
init::init();
}
模组.rs:
pub mod init;
mod game;
游戏.rs:
use ggez::event::EventHandler;
use ggez::{graphics, Context, GameResult};
pub struct MyGame {
// Your state here...
}
impl MyGame {
pub fn new(_ctx: &mut Context) -> MyGame {
// Load/create resources such as images here.
MyGame {
// ...
}
}
}
impl EventHandler for MyGame {
fn update(&mut self, _ctx: &mut Context) -> GameResult<()> {
// Update code here...
Ok(())
}
fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
graphics::clear(ctx, graphics::WHITE);
// Draw code here...
graphics::present(ctx)
}
}
初始化.rs:
use crate::game::game::MyGame;
use ggez::{ContextBuilder, event};
pub fn init() {
// Make a Context.
let (mut ctx, mut event_loop) = ContextBuilder::new("my_game", "Cool Game Author")
.build()
.expect("aieee, could not create ggez context!");
// Create an instance of your event handler.
// Usually, you should provide it with the Context object to
// use when setting your game up.
let mut my_game = MyGame::new(&mut ctx);
// Run!
match event::run(&mut ctx, &mut event_loop, &mut my_game) {
Ok(_) => println!("Exited cleanly."),
Err(e) => println!("Error occured: {}", e),
}
}
推荐阅读
- ip-address - 如何计算所需主机的 CIDR?
- javascript - 带有 npm 的 Webpack:模块动态导入
- sql-server - sp_send_dbmail - 无法附加查询结果
- apache-kafka - Kafka 消费者从最新开始
- emacs - 在为 emacs 安装 TRAMP 时,如何解决 `node`Installation' 缺少 XXX 的菜单项?
- java - Java如何使用递归和节点创建和有序的树结构?
- git - 将具有源历史记录的多个 Xcode 项目移动到新的 GitHub 存储库
- makefile - 如何在makefile中取消定义“多个”环境变量
- rest - JMeter 调用 kerberos 保护的 rest api 失败(在 IE 浏览器中工作)
- string - 用于字符串的 Hive XOR 函数?