为什么“类型参数从不使用”,即使它在 where 子句中使用?

Ser*_*sta 3 generics rust

我对 Rust 很陌生,我一直遇到这个问题,我不知道如何解决它。我有一个类似的结构,

pub struct Solver <'e, E: 'e, T, M, C>
    where
        E: Equation<T, M, C>,
        T: Term<C>,
        M: Mesh,
{
    equations: &'e [E],
}
Run Code Online (Sandbox Code Playgroud)

这总是给我这个错误,

pub struct Solver <'e, E: 'e, T, M, C>
    where
        E: Equation<T, M, C>,
        T: Term<C>,
        M: Mesh,
{
    equations: &'e [E],
}
Run Code Online (Sandbox Code Playgroud)

我知道它T从未被使用过,但是,例如,我无法定义方程式T(或者我可以吗?)。有没有更短的版本可以写?这PhantomData是我想避免的奇怪的事情,所以我不知道如何解决这个问题。

Tod*_*odd 6

当为泛型绑定类型时,绑定仅对使用绑定类型的功能(调用其方法或访问其字段等)的编译器有意义。通常没有必要以其他方式限制事物。这样做是有原因的,但最好仅在意识到需要时才添加这些理由。声明泛型参数时,同样适用。impl除非在结构中显式使用该参数,否则无论是否需要它都可能不需要添加它。

在下面的代码中,除了将其保存在数组中之外,Solver没有执行任何操作,因此可以是任何类型。E它很灵活。

pub trait Equation
{
    type T;
    fn eq(&self) -> Self::T;
}

pub struct Solver<'e, E: 'e>
{
    equations: &'e [E],
}

impl<'e, E: 'e> Solver<'e, E>
{
    fn get_e(&self, i: usize) -> &'e E
    {
        &self.equations[i]
    }
}
Run Code Online (Sandbox Code Playgroud)

现在假设Solver需要调用其数组中 的eq()方法。不过,到目前为止,还没有必要在结构定义中E设置界限。E边界仅在实现中才有意义。

pub struct Solver<'e, E: 'e>
{
    equations: &'e [E],
}

impl<'e, E: 'e, F> Solver<'e, E>
where 
    E: Equation<T = F>,
{
    fn get_e(&self, i: usize) -> &'e E
    {
        &self.equations[i]
    }
    fn e_eq(&self, i: usize) -> F
    {
        self.equations[i].eq()
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的内容编译得很好。该结构只关心它具有E任何类型并且其生命周期遵循'e. 并且impl有必要变得更加具体。

forimpl结构在这方面可以有些独立。直到需要调用它的返回.eq()类型并对其返回类型执行某些操作时,我们才添加任何约束。并且添加了一个新的通用参数,因为它必须是 - 立即使用它并且编译器会感到满意。

上面,返回的特定类型.eq()被推迟到泛型参数F。到目前为止,Solver可以接受任何E返回任何T尚未定义的类型(与Solver's相关联F)并从 中返回它e_eq()

为了更多地限制事物并确保任何从其方法返回 an 的E东西都可以被消除,并且类型在 的边界中指定:Solveri32eq()FE

impl<'e, E: 'e> Solver<'e, E>
where 
    E: Equation<T = i32>,
{
    fn get_e(&self, i: usize) -> &'e E
    {
        &self.equations[i]
    }
    fn e_eq(&self, i: usize) -> i32
    {
        self.equations[i].eq()
    }
}
Run Code Online (Sandbox Code Playgroud)

Solver到目前为止,所有的更改都是必然的,并且没有影响s struct的定义- 只是影响impl.

我个人发现推迟这样的事情是一个很好的方法。根据需要增量添加边界,同时不断确保代码构建过程中的每一步都可以节省时间,而不是提前声明几件事。如果我想到需要添加的几件事,我会将它们放在 TODO 注释中,然后一次修改一项。

如果您正在处理某种设计文档,而队友正在实现依赖于您提供的部分的内容,您可以将所需的方法添加到 并在impl需要的范围内工作,并保留方法主体空的unimplemented!(),里面有一个宏。让编译器提示您需要添加哪些边界。

struct仅当存在公共字段时才需要声明中的严格约束,并且程序的其他部分对这些字段支持哪些接口或属性进行假设。