如何处理或测试类型是否为 Rust 宏中的选项?
How can I handle or test if a type is an Option in a Rust macro?
我正在尝试创建一个宏来生成一个可以从 postgres 数据库填充的结构。
现在,由于数据库中有可为空和不可为空的字段,我想在宏中以不同方式处理它们。
输出应该是这样的结构:
#[derive(Debug, Default)]
pub struct MyStruct {
pub attrib_a: i64,
pub attrib_b: Option<i64>,
}
impl MyStruct {
pub fn get_row(&self, row: &postgres::rows::Row) -> MyStruct {
MyStruct {
// the non-nullable attrib_a, where I can for sure take the value out of the Option and assign it
attrib_a: match row.get::<_, Option<i64>>("attrib_a") {
Some(x) => x,
None => 0,
},
// here for the nullable attrib_b I just want to return the Option as is
attrib_b: row.get::<_, Option<i64>>("attrib_b"),
}
}
}
这是当前的宏代码:
macro_rules! make_table_struct {
($tname: stmt => $sname: ident; $($fname: ident: $ftype: ty),+) => {
#[derive(Debug, Clone, Default)]
pub struct $sname {
$(
pub $fname: $ftype,
)+
}
impl $sname
{
pub fn get_row(&self,row:&postgres::rows::Row)->$sname
{
$sname
{
//How do I know if I have an Option here or not and act then accordingly?
$(
$fname: row.get::<_,Option<$ftype>>(stringify!($fname)),
)+
}
}
}
}
}
宏调用:
make_table_struct! ("source_table_name" => MyStruct; attrib_a: i64, attrib_b: Option<i64>)
这是一个带有 $fname
和类型的宏,这可能是可选的。如果类型是可选的,它会生成另一个函数,如果不是:
macro_rules! make_get_row {
($fname: ident, Option<$ftype: ty>) => {
fn $fname(i: Option<$ftype>) -> i64 {
i.unwrap_or(0)
}
};
($fname: ident, $ftype: ty) => {
fn $fname(i: $ftype) -> i64 {
i
}
};
}
make_get_row!(direct, i64);
make_get_row!(via_op, Option<i64>);
fn main() {
direct(1);
via_op(Some(1));
}
您应该能够在 make_table_struct
.
中使用该宏的一个(可能经过调整的)变体
以下内容并非制作质量,但可能会带您到某个地方:
macro_rules! get_table_row {
($row: ident, nonnullable $fname:ident: $ftype:ty) => {
$row.get::<_,$ftype>(stringify!($fname))
};
($row: ident, nullable $fname:ident: $ftype:ty) => {
match $row.get::<_,Option<Option<$ftype>>>(stringify!($fname)) { Some(x) => x, None => Some(0) }
}
}
type nullable<T> = Option<T>;
type nonnullable<T> = T;
macro_rules! make_table_struct {
($tname:stmt => $sname:ident; $($nul: ident $fname:ident: $ftype:tt),+) => {
#[derive(Debug, Clone, Default)]
pub struct $sname {
$(
pub $fname: $nul < $ftype >,
)+
}
impl $sname {
pub fn get_row(&self, row: &postgres::rows::Row) -> $sname {
$(
let $fname = get_table_row!(row, $nul $fname: $ftype);
)+
$sname {
$($fname,)+
}
}
}
}
}
make_table_struct! ("source_table_name" => MyStruct; nonnullable attrib_a: i64, nullable attrib_b: i64);
我正在尝试创建一个宏来生成一个可以从 postgres 数据库填充的结构。 现在,由于数据库中有可为空和不可为空的字段,我想在宏中以不同方式处理它们。
输出应该是这样的结构:
#[derive(Debug, Default)]
pub struct MyStruct {
pub attrib_a: i64,
pub attrib_b: Option<i64>,
}
impl MyStruct {
pub fn get_row(&self, row: &postgres::rows::Row) -> MyStruct {
MyStruct {
// the non-nullable attrib_a, where I can for sure take the value out of the Option and assign it
attrib_a: match row.get::<_, Option<i64>>("attrib_a") {
Some(x) => x,
None => 0,
},
// here for the nullable attrib_b I just want to return the Option as is
attrib_b: row.get::<_, Option<i64>>("attrib_b"),
}
}
}
这是当前的宏代码:
macro_rules! make_table_struct {
($tname: stmt => $sname: ident; $($fname: ident: $ftype: ty),+) => {
#[derive(Debug, Clone, Default)]
pub struct $sname {
$(
pub $fname: $ftype,
)+
}
impl $sname
{
pub fn get_row(&self,row:&postgres::rows::Row)->$sname
{
$sname
{
//How do I know if I have an Option here or not and act then accordingly?
$(
$fname: row.get::<_,Option<$ftype>>(stringify!($fname)),
)+
}
}
}
}
}
宏调用:
make_table_struct! ("source_table_name" => MyStruct; attrib_a: i64, attrib_b: Option<i64>)
这是一个带有 $fname
和类型的宏,这可能是可选的。如果类型是可选的,它会生成另一个函数,如果不是:
macro_rules! make_get_row {
($fname: ident, Option<$ftype: ty>) => {
fn $fname(i: Option<$ftype>) -> i64 {
i.unwrap_or(0)
}
};
($fname: ident, $ftype: ty) => {
fn $fname(i: $ftype) -> i64 {
i
}
};
}
make_get_row!(direct, i64);
make_get_row!(via_op, Option<i64>);
fn main() {
direct(1);
via_op(Some(1));
}
您应该能够在 make_table_struct
.
以下内容并非制作质量,但可能会带您到某个地方:
macro_rules! get_table_row {
($row: ident, nonnullable $fname:ident: $ftype:ty) => {
$row.get::<_,$ftype>(stringify!($fname))
};
($row: ident, nullable $fname:ident: $ftype:ty) => {
match $row.get::<_,Option<Option<$ftype>>>(stringify!($fname)) { Some(x) => x, None => Some(0) }
}
}
type nullable<T> = Option<T>;
type nonnullable<T> = T;
macro_rules! make_table_struct {
($tname:stmt => $sname:ident; $($nul: ident $fname:ident: $ftype:tt),+) => {
#[derive(Debug, Clone, Default)]
pub struct $sname {
$(
pub $fname: $nul < $ftype >,
)+
}
impl $sname {
pub fn get_row(&self, row: &postgres::rows::Row) -> $sname {
$(
let $fname = get_table_row!(row, $nul $fname: $ftype);
)+
$sname {
$($fname,)+
}
}
}
}
}
make_table_struct! ("source_table_name" => MyStruct; nonnullable attrib_a: i64, nullable attrib_b: i64);