需要一个有序的向量来进行结构初始化。

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

require an ordered vector for struct initialization

问题

我有一个结构体:

pub struct OneDLookup<T: PartialOrd + Sub + Add + Copy + Clone, U: Add + Sub + Copy + Clone>{
    breakpoints: Vec<T>,
    values: Vec<U>,
    last_diff_bp: f64,      //忽略这些,它们对这个问题不重要
    last_diff_values: f64,
    first_diff_bp: f64,
    first_diff_values: f64,
}

这将用作查找表,但这个结构体必须满足两个重要条件:

  1. breakpoints 必须按升序排列,例如1、5、7、9,不能是其他顺序。
  2. breakpoints 和 values 必须具有相同的长度。

是否可能在编译时检查这些条件(或者在编写过程中使用 rust-analyzer 更好)?我担心可能不行。

我对 Rust 还很陌生,仍在学习其中的细节。

我尝试创建了一个小宏,基于 vec!() 宏,以查看我是否能够理解它是如何工作的,但不幸的是,我一点也不明白:

macro_rules! create_1d_lookup {
    (($($bps:expr,)*); ($($vals:expr,)*)) => (
        $crate::my_crate::OneDLookup::new(vec![$($bps),+], vec![$($vals),+])
    );
}

OneDLookup::new() 接受 breakpoints 和 values 向量作为参数。

这个结构体在初始化后不会改变。

英文:

I have a struct:

pub struct OneDLookup &lt;T: PartialOrd + Sub + Add + Copy + Clone, U: Add + Sub + Copy + Clone&gt;{
    breakpoints: Vec&lt;T&gt;,
    values: Vec&lt;U&gt;,
    last_diff_bp: f64,      //ignore these, they are not important to this question
    last_diff_values: f64,
    first_diff_bp: f64,
    first_diff_values: f64,
}

This will function as a lookup table, however there are 2 important things that have to be true about this struct:

breakpoints must be in ascending order 1,5,7,9 for example, and not any other order.
breakpoints and values must have the same length.

Is it possible to check these at compile time (or even better with the rust-analyzer during writing) in a macro? I fear it might not be.

I'm quite new to rust so I'm still learning the ins and outs.

I tried to make a tiny macro that doesn't work based on the vec!() macro to see if I could understand what was done there but unfortunately I have no idea:

macro_rules! create_1d_lookup {
    (($($bps:expr,)*); ($($vals:expr,)*)) =&gt; (
        $crate::my_crate::OneDLookup::new(vec![$($bps),+], vec![$($vals),+])
    );
}

OneDLookup::new() takes the breakpoints and values vectors as arguments.

This struct is constant and will not change after initialization.

答案1

得分: 2

您可以通过创建一个const来执行一些逻辑来验证不变量是否得以保持,并且如果它们被破坏,就会引发恐慌。恐慌将被转换为编译失败:

macro_rules! create_1d_lookup {
    (($($bps:expr,)*); ($($vals:expr,)*)) => {{
        const _: () = {
            let breakpoints = [ $($bps,)* ];
            if breakpoints.len() != [ $($vals,)* ].len() {
                // 有多种在宏中计数的方法,
                // 假设这些表达式没有副作用,这是最简单的方法。
                panic!("向量的大小不匹配");
            }

            let mut i = 1;
            // 当前无法在const中使用`for`循环。
            while i < breakpoints.len() {
                if breakpoints[i - 1] > breakpoints[i] {
                    panic!("断点未排序");
                }
                i += 1;
            }
        };
        $crate::my_crate::OneDLookup::new(vec![$($bps),+], vec![$($vals),+])
    }};
}

不幸的是,这是一种后单态化错误,这意味着它不会在cargo check中显示,只会在cargo build中显示。

英文:

You can do that by creating a const that runs some logic to verify the invariants are upheld and panics if they're broken. The panic will be translated into a compilation failure:

macro_rules! create_1d_lookup {
    (($($bps:expr,)*); ($($vals:expr,)*)) =&gt; {{
        const _: () = {
            let breakpoints = [ $($bps,)* ];
            if breakpoints.len() != [ $($vals,)* ].len() {
                // There are multiple ways to count in macros,
                // this is the simplest assuming the expressions are side-effect-free.
                panic!(&quot;sizes of vectors don&#39;t match&quot;);
            }

            let mut i = 1;
            // Can&#39;t use a `for` loop in consts currently.
            while i &lt; breakpoints.len() {
                if breakpoints[i - 1] &gt; breakpoints[i] {
                    panic!(&quot;breakpoints aren&#39;t sorted&quot;);
                }
                i += 1;
            }
        };
        $crate::my_crate::OneDLookup::new(vec![$($bps),+], vec![$($vals),+])
    }};
}

Unfortunately, this is a post-monomorphization error, meaning it won't show up in cargo check, only in cargo build.

huangapple
  • 本文由 发表于 2023年7月13日 20:47:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76679549.html
匿名

发表评论

匿名网友

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

确定