当其中一个是本地引用时,如何在类型约束中编写引用的生存期?

drh*_*gen 4 generics lifetime rust

我有一个特征Matrix和通用功能semi_def<T: Matrix>(x: &T),我想对该特征进行操作。该功能需要一个操作员特征,例如Mul,在上实现T。但是,如果引用之一是对局部变量的引用,我似乎无法使一生愉快。当其中之一只是本地临时引用时,如何在类型约束中编写引用的生存期?

use std::ops::Mul;

trait Matrix: Clone {
    fn transpose(self) -> Self;
}

#[derive(Clone)]
struct DenseMatrix {
    n_rows: usize,
    n_columns: usize,
    elements: Vec<f64>,
}

impl Matrix for DenseMatrix {
    fn transpose(self) -> Self {
        unimplemented!()
    }
}

impl<'a, 'b> Mul<&'b DenseMatrix> for &'a DenseMatrix {
    type Output = DenseMatrix;
    fn mul(self, _rhs: &'b DenseMatrix) -> Self::Output {
        unimplemented!()
    }
}

fn semi_def<'a, T: Matrix>(x: &'a T) -> T
where
    &'a T: Mul<&'a T, Output = T>,
{
    &(*x).clone().transpose() * x
}

fn main() {}
Run Code Online (Sandbox Code Playgroud)

这给出了这个错误:

use std::ops::Mul;

trait Matrix: Clone {
    fn transpose(self) -> Self;
}

#[derive(Clone)]
struct DenseMatrix {
    n_rows: usize,
    n_columns: usize,
    elements: Vec<f64>,
}

impl Matrix for DenseMatrix {
    fn transpose(self) -> Self {
        unimplemented!()
    }
}

impl<'a, 'b> Mul<&'b DenseMatrix> for &'a DenseMatrix {
    type Output = DenseMatrix;
    fn mul(self, _rhs: &'b DenseMatrix) -> Self::Output {
        unimplemented!()
    }
}

fn semi_def<'a, T: Matrix>(x: &'a T) -> T
where
    &'a T: Mul<&'a T, Output = T>,
{
    &(*x).clone().transpose() * x
}

fn main() {}
Run Code Online (Sandbox Code Playgroud)

drh*_*gen 5

您需要更高级别的特征范围(HRTB),这在高级Rust书籍Rustonomicon和堆栈溢出中都有描述。它们允许类型约束说特征不仅必须针对具有特定生存期的引用实现,而且还必须针对任何生存期实现。他们使用where for<>语法。这是函数定义,它表示对Mul以下任意两个引用都需要实现T:

fn semi_def<'a, T: Matrix>(x: &'a T) -> T
where
    for<'b, 'c> &'b T: Mul<&'c T, Output = T>,
{
    &(*x).clone().transpose() * x
}
Run Code Online (Sandbox Code Playgroud)

由于其中一个引用实际上具有使用期限'a,而不是局部使用期限,因此可以用稍微宽松一些的约束来编写:

fn semi_def<'a, T: Matrix>(x: &'a T) -> T
where
    for<'b> &'b T: Mul<&'a T, Output = T>,
{
    &(*x).clone().transpose() * x
}
Run Code Online (Sandbox Code Playgroud)

该问答基于我对Rust用户的邮件提出的问题,我对其进行了清理,并带到这里供以后的Rustaceans使用。