在Rust中,有没有一种方法使函数接受两种类型而无需trait?

huangapple go评论68阅读模式
英文:

In Rust, is there a way to make function accept two types without a trait?

问题

我对Rust还不太了解。我的问题更多是理论性的。问题是这样的。

我有一个状态机(用于通过quick-xml crate解析XML,但对于这个问题来说并不重要),其转换逻辑由一个match表达式控制。表达式的许多分支具有额外的匹配保护条件。这些匹配保护条件大多相同,看起来像这样:

Event::Start(bs: BytesStart) if bs.local_name().as_ref() == b"any-tag" => NextState,
// 和
Event::End(be: BytesEnd) if be.local_name().as_ref() == b"any-tag" => SomeOtherState,

为了清理代码,我想将相等比较移到一个单独的函数中,如下所示:

fn tag_is(tag: &<要么是BytesStart要么是BytesEnd>, assertion: &str) -> bool {
    tag.local_name().as_ref() == assertion.as_bytes()
}
// 并使用它
Event::Start(bs: BytesStart) if tag_is(&bs, "any-tag") => NextState,

BytesStartBytesEnd 是不同的结构/类型,并且都有自己的 .local_name() 方法。如果.local_name()定义在某个trait(TraitWithLocalName)中,并且为两者都实现了,那么我可以编写一个泛型函数如下:

fn tag_is(tag: &impl TraitWithLocalName, assertion: &str) -> bool {...}

所以,问题是,如何处理这种情况 - 当一个函数可能接受不同类型的参数,这些参数没有共享相同的trait呢?

英文:

I am pretty new to Rust. My question is more theoretical. The problem is this.

I have a state machine (to parse XML via quick-xml crate but this is not important for this question) whose transition logic is controlled by a match expression. A lot of branches of the expression have additional match guards. Most of those match guards are pretty identical and look like:

Event::Start(bs: BytesStart) if bs.local_name().as_ref() == b&quot;any-tag&quot; =&gt; NextState,
// and
Event::End(be: BytesEnd) if be.local_name().as_ref() == b&quot;any-tag&quot; =&gt; SomeOtherState,

To clean up the code I would like to move that equality comparison to a separate function, like:

fn tag_is(tag: &amp;&lt;either BytesStart or BytesEnd&gt;, assertion: &amp;str) -&gt; bool {
    tag.local_name().as_ref() == assertion.as_bytes()
}
// and use it
Event::Start(bs: BytesStart) if tag_is(&amp;bs, &quot;any-tag&quot;) =&gt; NextState,

BytesStart and BytesEnd are different structs/types, and both have their own .local_name() methods. If the .local_name() was defined in some trait (TraitWithLocalName) and implemented for both, then I would write a generic like:

fn tag_is(tag: &amp;impl TraitWithLocalName, assertion: &amp;str) -&gt; bool {...}

So, the question is, how to deal with that kind of situation - when a function might accept various types of an argument, which don't share the same trait?

答案1

得分: 3

你可以编写自己的 trait,其中包含这个函数,并为 BytesStartBytesEnd 都实现它。

英文:

You can write your own trait that has this function and implement it for both BytesStart and BytesEnd.

答案2

得分: 0

你不能用一个函数来做这个。如果你真的想的话,可以尝试用宏来实现。我强烈建议定义自己的特性来完成这个任务,但这取决于你。

macro_rules! tag_is {
    ($x: expr, $assertion: expr) => {{
        let assertion: &str = $assertion; // 类型检查 - 确保 assertion 是一个字符串。
        let s: &[u8] = $x.local_name().as_ref();
        s == assertion.as_bytes()
    }} 
}

struct BytesStart;

impl BytesStart {
    fn local_name(&self) -> &str {
        "hello"
    }
}

struct BytesEnd;

impl BytesEnd {
    fn local_name(&self) -> &[u8] {
        b"any-tag"
    }
}

pub fn main() {
    println!("{}", tag_is!(BytesStart, "any-tag")); // false
    println!("{}", tag_is!(BytesEnd, "any-tag")); // true
}
英文:

You cannot do this with a function. If you really wanted to, you could try doing it with a macro. I would strongly prefer defining my own trait to doing things this way, but it's up to you.

macro_rules! tag_is {
    ($x: expr, $assertion: expr) =&gt; {{
        let assertion: &amp;str = $assertion; // type checking - makes sure assertion is a str.
        let s: &amp;[u8] = $x.local_name().as_ref();
        s == assertion.as_bytes()
    }} 
}

struct BytesStart;

impl BytesStart {
    fn local_name(&amp;self) -&gt; &amp;str {
        &quot;hello&quot;
    }
}

struct BytesEnd;

impl BytesEnd {
    fn local_name(&amp;self) -&gt; &amp;[u8] {
        b&quot;any-tag&quot;
    }
}

pub fn main() {
    println!(&quot;{}&quot;, tag_is!(BytesStart, &quot;any-tag&quot;)); // false
    println!(&quot;{}&quot;, tag_is!(BytesEnd, &quot;any-tag&quot;)); // true
}

huangapple
  • 本文由 发表于 2023年6月8日 18:49:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/76431066.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定