gpt4 book ai didi

rust - 根据编译目标操作系统,Rust 中将不同类型的值分配给变量的惯用方式是什么?

转载 作者:行者123 更新时间:2023-12-03 07:37:21 48 4
gpt4 key购买 nike

我正在开发一个绑定(bind)到 Tokio 套接字并管理 TCP 连接的代码库。在生产中,它绑定(bind)到 AF_VSOCK使用 tokio-vsock 箱。
在 Mac 上本地开发时,AF_VSOCK API 不可用,因为没有 hypervisor -> VM连接——它只是使用 cargo run 本地运行.
在本地运行时,我一直在创建标准 tokio::net::TcpListener struct 并且在生产中我一直在创建 tokio_vsock::VsockListener .这两种结构大多是可互换的,并且公开了相同的方法。无论使用哪种结构,其余代码都能完美运行。
到目前为止,我只保留了这两个结构,并简单地注释掉了本地不需要的结构——这显然不是“好的做法”。我的代码如下:

#[tokio::main]
async fn main() -> Result<(), ()> {
// Production AF_VSOCK listener (comment out locally)
let mut listener = tokio_vsock::VsockListener::bind(
&SockAddr::Vsock(
VsockAddr::new(
VMADDR_CID_ANY,
LISTEN_PORT,
)
)
)
.expect("Unable to bind AF_VSOCK listener");

// Local TCP listener (comment out in production)
let mut listener = tokio::net::TcpListener::bind(
std::net::SocketAddr::new(
std::net::IpAddr::V4(
std::net::Ipv4Addr::new(0, 0, 0, 0)
),
LISTEN_PORT as u16,
)
)
.await
.expect("Unable to bind TCP listener");

// This works regardless of which listener is used
let mut incoming = listener.incoming();

while let Some(socket) = incoming.next().await {
match socket {
Ok(mut stream) => {
// Do something
}
}
}

Ok(())
}
我尝试使用 cfg!()带有 target_os 的宏设置为条件,但编译器提示 bind() 返回的类型方法不匹配。
我的问题是:根据编译目标操作系统,Rust 中将不同类型的不同值分配给变量的惯用方式是什么?

最佳答案

有多种选择。就 stdlib 本身的使用而言,最简单和最常见的方法是使用 #[cfg]。宏(而不是 cfg!() 。以下代码片段阐明了它的用法:

struct Linux;
impl Linux {
fn x(&self) -> Linux {
println!("Linux");
Linux
}
}

struct Windows;
impl Windows {
fn x(&self) -> Windows {
println!("Windows");
Windows
}
}

fn main() {
#[cfg(not(target_os = "linux"))]
let obj = {
let obj = Linux;
obj
};
#[cfg(not(target_os = "windows"))]
let obj = {
let obj = Windows;
obj
};
let _ = obj.x();
}
(见 https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7088980d24c4a960c2158b091899d24d)。
在您的情况下,这将是(未经测试):
#[tokio::main]
async fn main() -> Result<(), ()> {
#[cfg(target_os = "linux")]
let mut listener = tokio_vsock::VsockListener::bind(
&SockAddr::Vsock(
VsockAddr::new(
VMADDR_CID_ANY,
LISTEN_PORT,
)
)
)
.expect("Unable to bind AF_VSOCK listener");

#[cfg(target_os = "Mac")]
let mut listener = tokio::net::TcpListener::bind(
std::net::SocketAddr::new(
std::net::IpAddr::V4(
std::net::Ipv4Addr::new(0, 0, 0, 0)
),
LISTEN_PORT as u16,
)
)
.await
.expect("Unable to bind TCP listener");
...
}
查看 https://doc.rust-lang.org/reference/conditional-compilation.html对于可用条件,包括功能标志,以防 target_os 不够适用。 #[cfg] 之间的主要区别和 cfg!()cfg!不删除代码。根据它的文档:“cfg!与#[cfg] 不同,它不会删除任何代码,只会评估为真或假”。因此,在使用 #[cfg] 时会出现编译错误更类似于 C/C++ 中的 if-defs 并删除未使用的代码,因此编译器永远不会看到类型不匹配。

关于rust - 根据编译目标操作系统,Rust 中将不同类型的值分配给变量的惯用方式是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65628591/

48 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com