我有一个Fibonacci
结构,可以用作实现One
,Zero
,Add
和Clone
的任何事物的迭代器。这适用于所有整数类型。
我想将此结构用于BigInteger
类型,这些类型使用Vec
实现,并且调用clone()
的费用很高。我想对Add
的两个引用使用T
,然后返回一个新的T
(不再克隆)。
对于我的生活,我不能制作一个可以编译的...
工作:
extern crate num;
use std::ops::Add;
use std::mem;
use num::traits::{One, Zero};
pub struct Fibonacci<T> {
curr: T,
next: T,
}
pub fn new<T: One + Zero>() -> Fibonacci<T> {
Fibonacci {
curr: T::zero(),
next: T::one(),
}
}
impl<'a, T: Clone + Add<T, Output = T>> Iterator for Fibonacci<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
mem::swap(&mut self.next, &mut self.curr);
self.next = self.next.clone() + self.curr.clone();
Some(self.curr.clone())
}
}
#[test]
fn test_fibonacci() {
let first_12 = new::<i64>().take(12).collect::<Vec<_>>();
assert_eq!(vec![1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144], first_12);
}
所需:
extern crate num;
use std::ops::Add;
use std::mem;
use num::traits::{One, Zero};
pub struct Fibonacci<T> {
curr: T,
next: T,
}
pub fn new<T: One + Zero>() -> Fibonacci<T> {
Fibonacci {
curr: T::zero(),
next: T::one(),
}
}
impl<'a, T: Clone + 'a> Iterator for Fibonacci<T>
where
&'a T: Add<&'a T, Output = T>,
{
type Item = T;
fn next(&mut self) -> Option<T> {
mem::swap(&mut self.next, &mut self.curr);
self.next = &self.next + &self.curr;
Some(self.curr.clone())
}
}
#[test]
fn test_fibonacci() {
let first_12 = new::<i64>().take(12).collect::<Vec<_>>();
assert_eq!(vec![1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144], first_12);
}
这给出了错误
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src/main.rs:27:21
|
27 | self.next = &self.next + &self.curr;
| ^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 25:5...
--> src/main.rs:25:5
|
25 | / fn next(&mut self) -> Option<T> {
26 | | mem::swap(&mut self.next, &mut self.curr);
27 | | self.next = &self.next + &self.curr;
28 | | Some(self.curr.clone())
29 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:27:21
|
27 | self.next = &self.next + &self.curr;
| ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 19:1...
--> src/main.rs:19:1
|
19 | / impl<'a, T: Clone + 'a> Iterator for Fibonacci<T>
20 | | where
21 | | &'a T: Add<&'a T, Output = T>,
22 | | {
... |
29 | | }
30 | | }
| |_^
note: ...so that types are compatible (expected std::ops::Add, found std::ops::Add<&'a T>)
--> src/main.rs:27:32
|
27 | self.next = &self.next + &self.curr;
| ^
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src/main.rs:27:34
|
27 | self.next = &self.next + &self.curr;
| ^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 25:5...
--> src/main.rs:25:5
|
25 | / fn next(&mut self) -> Option<T> {
26 | | mem::swap(&mut self.next, &mut self.curr);
27 | | self.next = &self.next + &self.curr;
28 | | Some(self.curr.clone())
29 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:27:34
|
27 | self.next = &self.next + &self.curr;
| ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 19:1...
--> src/main.rs:19:1
|
19 | / impl<'a, T: Clone + 'a> Iterator for Fibonacci<T>
20 | | where
21 | | &'a T: Add<&'a T, Output = T>,
22 | | {
... |
29 | | }
30 | | }
| |_^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:27:34
|
27 | self.next = &self.next + &self.curr;
| ^^^^^^^^^^
答案 0 :(得分:7)
如何写一个特征绑定添加两个泛型类型的引用?
让我们从一个简化的例子开始:
fn add_things<T>(a: &T, b: &T) {
a + b;
}
这有错误
error[E0369]: binary operation `+` cannot be applied to type `&T`
--> src/lib.rs:2:5
|
2 | a + b;
| ^^^^^
|
= note: an implementation of `std::ops::Add` might be missing for `&T`
正如编译器提示的那样,我们需要保证为Add
实现&T
。我们可以直接通过向我们的类型添加显式生存期来表达它,并在我们的特征界限中使用它:
use std::ops::Add;
fn add_things<'a, T>(a: &'a T, b: &'a T)
where
&'a T: Add,
{
a + b;
}
接下来,让我们尝试一种稍微不同的方法 - 我们将在函数内部创建一个,而不是提交引用:
fn add_things<T>(a: T, b: T) {
let a_ref = &a;
let b_ref = &b;
a_ref + b_ref;
}
我们得到同样的错误:
error[E0369]: binary operation `+` cannot be applied to type `&T`
--> src/lib.rs:5:5
|
5 | a_ref + b_ref;
| ^^^^^^^^^^^^^
|
= note: an implementation of `std::ops::Add` might be missing for `&T`
但是,尝试添加与以前相同的修复程序不起作用。它也有点尴尬,因为生命周期与传入的任何参数无关:
use std::ops::Add;
fn add_things<'a, T: 'a>(a: T, b: T)
where
&'a T: Add,
{
let a_ref = &a;
let b_ref = &b;
a_ref + b_ref;
}
error[E0597]: `a` does not live long enough
--> src/lib.rs:7:17
|
3 | fn add_things<'a, T: 'a>(a: T, b: T)
| -- lifetime `'a` defined here
...
7 | let a_ref = &a;
| ^^
| |
| borrowed value does not live long enough
| assignment requires that `a` is borrowed for `'a`
...
11 | }
| - `a` dropped here while still borrowed
将'a
生命周期放在impl
上意味着该方法的调用者可以确定生命周期应该是什么。由于引用是在方法内部进行的,因此调用者甚至无法看到生命周期是什么。
相反,您希望限制任意生命周期的引用实现特征。这称为Higher Ranked Trait Bound(HRTB):
use std::ops::Add;
fn add_things<T>(a: T, b: T)
where
for<'a> &'a T: Add,
{
let a_ref = &a;
let b_ref = &b;
a_ref + b_ref;
}
应用回原始代码,你非常接近:
impl<T> Iterator for Fibonacci<T>
where
T: Clone,
for<'a> &'a T: Add<Output = T>,
{
type Item = T;
fn next(&mut self) -> Option<T> {
mem::swap(&mut self.next, &mut self.curr);
self.next = &self.next + &self.curr;
Some(self.curr.clone())
}
}
另见: