当前位置: 首页 > 知识库问答 >
问题:

程序宏如何检查选项的泛型类型并将其展平为单个选项?

刘松
2023-03-14

我正在编写一个派生过程宏,其中所有值都转换为选项。问题是结构中的任何选项字段都可以包含在这些选项类型中。就其本身而言,在我开始用serde序列化数据之前,这并不是什么大问题。我希望能够跳过值为None的任何值,但在某些情况下,它会变成Some(None)Some(CustomOption::None)。这两种情况并不比简单的None更有意义,但我不能只在派生字段上编写#[serde(skip_serialization_if=“Option::is_None”)]。当然,它们以JSON格式输出一个null值。

基本上,我希望能够使用syn库检查派生字段的内部值的类型是否为选项,并将其展平为单个选项

我可以想出两种解决这个问题的方法,但我真的想不出如何实施它们。第一种方法是遍历所有字段,找到选项s,然后打开这些选项并重新包装,使它们的外部只有一个选项。此解决方案的一个潜在问题是,在完成计算后,我可能必须在另一个选项中重新编写它们。第二种解决方案是找到选项,并相应地修改生成的代码,这样,如果内部选项包含None,则整个内容变为None;如果字段是选项,则基本上只有一个输出布尔值的辅助函数。有没有关于如何实施这些或更好的解决方案的想法?

下面是一个代码示例:

#[derive(Macro)]
struct X {
    a: usize,
    b: SomeType<String>,
    c: Option<String>,
}
struct GeneratedX {
    a: Option<usize>,
    b: Option<SomeType<String>>,
    c: Option<Option<String>>,
}

使用类似的函数包装选项中的所有值:

pub fn wrap_typ_in_options(&self) -> TokenStream {
    // self is a struct with the type Type in it along with some other items.
    let typ: syn::Type = self.typ();

    // attribute to check if should ignore a field.
    if self.should_ignore() {
        quote! { Option<#typ> }
    } else {
        quote! { Option<<#typ as module::Trait>::Type> }
    }
}

共有1个答案

徐兴昌
2023-03-14

根据我在原始帖子中的第二个想法,我找到了解决这个问题的方法。我使用了这样一个函数来判断令牌是否是一个选项

let idents_of_path = path
    .segments
    .iter()
    .fold(String::new(), |mut acc, v| {
        acc.push_str(&v.ident.to_string());
        acc.push(':');
        acc
    });
vec!["Option:", "std:option:Option:", "core:option:Option:"]
    .into_iter()
    .find(|s| idents_of_path == *s)
    .and_then(|_| path.segments.last())

然后,我添加了一个名为is_option的新方法,如果Type::Path是一个选项,该方法将返回布尔值。

pub fn is_option(&self) -> bool {
    let typ = self.typ();

    let opt = match typ {
        Type::Path(typepath) if typepath.qself.is_none() => Some(typepath.path.clone()),
        _ => None,
    };

    if let Some(o) = opt {
        check_for_option(&o).is_some()
    } else {
        false
    }
}

我根据此调用的结果修改了生成的代码,其方式类似于我处理各种属性的方式。所有这些对于我的特定用例应该都很好,因为没有别名的Option将被引入这个生态系统。这有点乱,但现在已经完成了。

 类似资料:
  • 我在我的一个实用程序类中有一个方法,它接受一个集合和一个类对象,并返回一个Iterable实例,该实例可以遍历作为指定类实例的集合的所有成员。其签名为: 这对于大多数用例都非常有效,但现在我需要将其与泛型类

  • “绑定不匹配:Team类型不是league类型 的有界参数 >的有效替代品。”

  • 我正在尝试有一个通量通用转换器使用通用类型在Java 8。我把我的代码建立在这个答案的基础上。其思想基本上是实现这个特定的转换器->: 类型转换器->转换为我想要的任何类型。因此,我正在使用构造函数创建一个类型为的类,并返回一个方法。我想在调用上创建类似这样的多个条目:,但类类型不同。但它甚至对整数也不起作用。 当我使用此单元测试进行测试时,我得到错误:。

  • 我有一个表单,其中包含一个免费选项和一个付费选项。 如果用户选择了一个付费选项,我想要显示一个不同于如果他们按下免费选项的按钮。 形式: 我想要的是: 我不确定如何在用户完成表单时实时实现这一点,我假设它是Javascript,但我不确定如何实现?多谢了。 编辑: 按钮会将用户带到付款处理程序,而另一个处理程序只需填写/提交表单即可。 编辑2: 这是我使用的支付处理器: 所以我真的必须用上面的表单

  • 问题内容: 我使用整数对选择进行排序,并且可以正常工作,当我尝试修改程序以使用泛型时,编译器会抱怨并且我不知道如何解决它。如果有人能提出一些建议和建设性的意见,我将不胜感激。这是代码。 以下是吐出来的东西。 cannot be applied to given types; printArray(list); ^ required: E[] found: int[] reason: inferre

  • 问题内容: 我是Java泛型的新手,来自.NET世界,我习惯于编写这样的方法: 该方法接受通用类型的对象,并检查该对象是否实现通用接口的 特定 版本,在这种情况下为。 现在,在Java中,我可以执行以下操作: 但 Java并 没有 让我做 据我所知,由于类型擦除,通常在Java中,此类将由类对象处理,我们将执行以下操作: 但是由于我要检查的类型是通用接口,所以您不能这样做: 那么,如何在Java中