gpt4 book ai didi

rust - 为什么二元运算符的这个结果需要适当的生命周期?

转载 作者:行者123 更新时间:2023-11-29 08:25:12 26 4
gpt4 key购买 nike

这与 my earlier question 有关关于使模幂方法通用。我现在得到以下代码:

fn powm<T>(fbase: &T, exponent: &T, modulus: &T) -> T
where
T: Mul<T, Output = T>
+ From<u8>
+ PartialEq<T>
+ Rem<T, Output = T>
+ Copy
+ for<'a> Rem<&'a T, Output = T>
+ Clone
+ PartialOrd<T>
+ ShrAssign<T>,
for<'a> &'a T: PartialEq<T> + Rem<&'a T, Output = T>,
{
if modulus == T::from(1) {
T::from(0)
} else {
let mut result = T::from(1);
let mut base = fbase % modulus;
let mut exp = exponent.clone();
while exp > T::from(0) {
if exp % T::from(2) == T::from(1) {
result = (result * base) % modulus;
}
exp >>= T::from(1);
base = (base * base) % modulus;
}
result
}
}

据我了解,通过定义特征界限 where for<'a> &'a T: Rem<&'a T, Output=T>据了解,我可以使用模运算符 %&'a T 类型的两个操作数上, 结果将是 T 类型.但是,我收到以下错误:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:20:30
|
20 | let mut base = fbase % modulus;
| ^
|
note: first, the lifetime cannot outlive the anonymous lifetime #3 defined on the function body at 3:1...
--> src/main.rs:3:1
|
3 | / fn powm<T>(fbase: &T, exponent: &T, modulus: &T) -> T
4 | | where
5 | | T: Mul<T, Output = T>
6 | | + From<u8>
... |
30 | | }
31 | | }
| |_^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:20:32
|
20 | let mut base = fbase % modulus;
| ^^^^^^^
note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the function body at 3:1...
--> src/main.rs:3:1
|
3 | / fn powm<T>(fbase: &T, exponent: &T, modulus: &T) -> T
4 | | where
5 | | T: Mul<T, Output = T>
6 | | + From<u8>
... |
30 | | }
31 | | }
| |_^
note: ...so that types are compatible (expected std::ops::Rem, found std::ops::Rem<&T>)
--> src/main.rs:20:30
|
20 | let mut base = fbase % modulus;
| ^

如果我用

替换有问题的行,代码确实有效
let mut base = fbase.clone() % modulus;

如果我已经可以使用模运算符来返回 T 类型的“新鲜”元素,我不明白为什么我首先需要克隆.我是否需要改为修改我的特征范围?为什么会出错?

最佳答案

编程时,学习如何创建 Minimal, Complete, and Verifiable example (MCVE) 非常有用.这使您可以忽略不相关的细节并专注于问题的核心。

举个例子,您的整个代码块可以缩减为:

use std::ops::Rem;

fn powm<T>(fbase: &T, modulus: &T)
where
for<'a> &'a T: Rem<&'a T, Output = T>,
{
fbase % modulus;
}

fn main() {}

拥有 MCVE 后,您可以对其进行排列以进行探索。例如,我们可以删除 the lifetime elision :

fn powm<'a, 'b, T>(fbase: &'a T, modulus: &'b T)
where
for<'x> &'x T: Rem<&'x T, Output = T>,
{
fbase % modulus;
}

现在我们开始看到一些东西:三个生命之间的关系是什么?好吧,没有一个,真的。如果我们制造一个会怎样?

  • 如果说输入引用可以统一为同一个终生有效:

    fn powm<'a, T>(fbase: &'a T, modulus: &'a T)
  • 如果我们说 'b'a 长,它有效:

    fn powm<'a, 'b: 'a, T>(fbase: &'a T, modulus: &'b T)
  • 如果我们说我们可以在运算符中有两个不同的生命周期,它是有效的:

    for<'x, 'y> &'x T: Rem<&'y T, Output = T>,

如果我们戳一下调用点呢?

  • 如果我们直接调用Rem::rem 方法,它会起作用:

    Rem::rem(fbase, modulus);
  • 如果我们取消引用和重新引用,它会起作用:

    &*fbase % &*modulus;

我不知道确切为什么原来的不起作用——从概念上讲,两个输入引用都应该能够统一到一个生命周期。可能存在不能或没有发生的推论,但我不知道。

与 Rust 编译器开发人员的进一步讨论导致 an issue因为它看起来不太对。此问题现已resolved理论上应该在 Rust 1.23 中可用。

关于rust - 为什么二元运算符的这个结果需要适当的生命周期?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46857955/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com