Rust Inari crate – 在类型未实现 Float trait 时使用泛型函数作为 trait 的一部分

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

Rust Inari crate - Using a generic function with Float as a trait when the type doesn't implement the Float trait

问题

抱歉,由于您的要求,我只会返回翻译好的部分。以下是您提供的内容的翻译:

我对Rust还很陌生,如果我有什么误解,提前道歉。

我在Rust中有一些代码,其中包括像这样的通用函数:

pub(crate) fn square_root<T: Float>(value_array: &[T]) -> T {
    value_array[0].sqrt()
}

我还有这个宏:

macro_rules! print_queries {
    ($INTERVAL:ty, $INTERVAL_INIT:expr, $TYPE_NAME:expr, $METHOD:expr, $PRINT_METHOD:expr, $VARIABLE_COUNT:expr) => {
        {
            let mut used_variables: Vec<$INTERVAL> = Vec::with_capacity($VARIABLE_COUNT);
            for i in 0..$VARIABLE_COUNT {
                used_variables.push($INTERVAL_INIT(COMP_DOUBLES[i]));
            }
            match std::panic::catch_unwind(|| $METHOD(&used_variables)) {
                Ok(result) => {
                    println!("{}: ", $TYPE_NAME);
                    print_query(lower(result), upper(result), $PRINT_METHOD(COMP_GMP_RATIONALS.as_slice()));
                }
                Err(_) => {
                    println!("{}: ", $TYPE_NAME);
                    print_query(1.0, -1.0, $PRINT_METHOD(COMP_GMP_RATIONALS.as_slice()));
                }
            }
        }
    }
}

宏与第一个函数一起使用作为参数$METHOD,例如:

print_queries!(InariInterval, inari_interval, "INARI", square_root, print_square_root, 1);

如您所见,我正在使用Inari crate中的这种方法,这是一个用于区间算术的crate:https://docs.rs/inari/latest/inari/index.html
InariInterval是inari::Interval类型的副本,inari_interval是从一个浮点数创建Interval的方法。

然而,这不起作用,这是我得到的错误:

error[E0277]: the trait bound `inari::Interval: num_traits::Float` is not satisfied
   --> src/query.rs:65:5
    |
65  |     run_query!(square_root, print_square_root, 1, square_root_range, check_input_square_root);
    |     ^^^^^^^^^^^-----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |     |          |
    |     |          required by a bound introduced by this call
    |     the trait `num_traits::Float` is not implemented for `inari::Interval`
    |
    = help: the following other types implement trait `num_traits::Float`:
              f32
              f64
note: required by a bound in `methods::square_root`
   --> src/methods.rs:803:30
    |
803 | pub(crate) fn square_root<T: Float>(value_array: &[T]) -> T {
    |                              ^^^^^ required by this bound in `square_root`

我希望尽量保持我的函数通用。我认为我不能在不使用Float的情况下实现square_root,而且这只能部分解决问题,因为我有其他具有相同问题的函数。

我尝试为Inari实现Float trait,但似乎不可能。我得到了这个错误:Only traits defined in the current crate can be implemented for arbitrary types [E0117]

因此,我有点陷入困境,不知道是否可以在保持函数通用的同时找到解决方案。

提前感谢您的帮助和建议。

英文:

I am quite new to Rust, so sorry by advance if I'm misunderstanding something.

I have some code in Rust where I have generic functions such as this one :

pub(crate) fn square_root&lt;T: Float&gt;(value_array: &amp;[T]) -&gt; T {
    value_array[0].sqrt()
}

I also have this macro :

macro_rules! print_queries {
    ($INTERVAL:ty, $INTERVAL_INIT:expr, $TYPE_NAME:expr, $METHOD:expr, $PRINT_METHOD:expr, $VARIABLE_COUNT:expr) =&gt; {
        {
            let mut used_variables: Vec&lt;$INTERVAL&gt; = Vec::with_capacity($VARIABLE_COUNT);
            for i in 0..$VARIABLE_COUNT {
                used_variables.push($INTERVAL_INIT(COMP_DOUBLES[i]));
            }
            match std::panic::catch_unwind(|| $METHOD(&amp;used_variables)) {
                Ok(result) =&gt; {
                    println!(&quot;{}: &quot;, $TYPE_NAME);
                    print_query(lower(result), upper(result), $PRINT_METHOD(COMP_GMP_RATIONALS.as_slice()));
                }
                Err(_) =&gt; {
                    println!(&quot;{}: &quot;, $TYPE_NAME);
                    print_query(1.0, -1.0, $PRINT_METHOD(COMP_GMP_RATIONALS.as_slice()));
                }
            }
        }
    }
}

The macro is used with the first function as the parameter $METHOD, e.g.

print_queries!(InariInterval, inari_interval, &quot;INARI&quot;, square_root, print_square_root, 1);

As you can see, I'm using this method with the Inari crate, which is a crate for interval arithmetic : https://docs.rs/inari/latest/inari/index.html
InariInterval is a copy of the type inari::Interval, and inari_interval is a method creating an Interval from one float.

However, this does not work, and here is the error I get :

error[E0277]: the trait bound `inari::Interval: num_traits::Float` is not satisfied
   --&gt; src/query.rs:65:5
    |
65  |     run_query!(square_root, print_square_root, 1, square_root_range, check_input_square_root);
    |     ^^^^^^^^^^^-----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |     |          |
    |     |          required by a bound introduced by this call
    |     the trait `num_traits::Float` is not implemented for `inari::Interval`
    |
    = help: the following other types implement trait `num_traits::Float`:
              f32
              f64
note: required by a bound in `methods::square_root`
   --&gt; src/methods.rs:803:30
    |
803 | pub(crate) fn square_root&lt;T: Float&gt;(value_array: &amp;[T]) -&gt; T {
    |                              ^^^^^ required by this bound in `square_root`

I'd like as much as possible to keep my functions generic. I don't think I can implement square_root without using Float, and that would only partly solve the problem since I have other functions with the same issue.

I tried to implement the Float trait for Inari but it doesn't seem to be possible. I got this error : Only traits defined in the current crate can be implemented for arbitrary types [E0117]

Thus, I'm a little bit stuck and I don't know if I can find a solution while keeping my functions generic.

Thanks for advance for your help and suggestions.

答案1

得分: 1

你有几个选择:

  • 请inari的维护者添加一个impl,可能放在一个功能标志后面。
  • 制作自己的trait,而不是使用Float
  • 制作自己的类型,而不是使用Interval

第一种选择是理想的,但如果Float对于间隔来说太具体,可能不可行。否则,第二种选择可能是最好的,尽管您随后将负责为现有类型(如f32f64和其他crates的浮点数)实现此trait。第三种选择与第二种类似,但将使您负责为您的类型实现现有的traits

此外,除非绝对需要,否则不要使用catch_unwind。恐慌意味着不可恢复,所以如果您预期出现错误,请使用OptionResult,以便真正不可恢复的错误不被忽略。

pub(crate) fn square_root&lt;T: Float&gt;(value_array: &amp;[T]) -&gt; Option&lt;T&gt; {
    // `first` is the same as `get(0)`
    value_array.first().map(|value| value.sqrt())
}

// inside the macro
match $METHOD(&amp;used_variables) {
    Some(result) =&gt; {
        println!(&quot;{}: &quot;, $TYPE_NAME);
        print_query(lower(result), upper(result), $PRINT_METHOD(COMP_GMP_RATIONALS.as_slice()));
    }
    None =&gt; {
        println!(&quot;{}: &quot;, $TYPE_NAME);
        print_query(1.0, -1.0, $PRINT_METHOD(COMP_GMP_RATIONALS.as_slice()));
    }
}
英文:

You have a couple options:

  • Ask the inari maintainers to add an impl, possibly behind a feature flag.
  • Make your own trait instead of using Float.
  • Make your own type instead of using Interval.

The first would be ideal, but it may not be possible if Float is too specific for intervals. Otherwise, the second is probably the best, although you would then be responsible for implementing this trait for existing types, such as f32, f64, and other crates' floats. The third is similar to the second, but would make you responsible for implementing existing traits for your type.

Also, don't use catch_unwind unless you absolutely need to. Panics are meant to be unrecoverable, so if you are expecting an error, use an Option or Result so that truly unrecoverable errors are not ignored.

pub(crate) fn square_root&lt;T: Float&gt;(value_array: &amp;[T]) -&gt; Option&lt;T&gt; {
    // `first` is the same as `get(0)`
    value_array.first().map(|value| value.sqrt())
}

// inside the macro
match $METHOD(&amp;used_variables) {
    Some(result) =&gt; {
        println!(&quot;{}: &quot;, $TYPE_NAME);
        print_query(lower(result), upper(result), $PRINT_METHOD(COMP_GMP_RATIONALS.as_slice()));
    }
    None =&gt; {
        println!(&quot;{}: &quot;, $TYPE_NAME);
        print_query(1.0, -1.0, $PRINT_METHOD(COMP_GMP_RATIONALS.as_slice()));
    }
}

huangapple
  • 本文由 发表于 2023年5月25日 06:52:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/76327873.html
匿名

发表评论

匿名网友

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

确定