我想在Rust中定义一个特征,它有一个泛型类型参数--比如说,在特征级别上是BorrowedValue,在它的方法级别上有一个生命周期 参数,比如说'a.复杂之处在于方法参数的实际类型是这两者的组合,即BorrowedValue<'a>.这可能最好用代码来说明:

// Constructs a borrowed value with a specific lifetime
trait ConstructI32AsBorrowed<'a>: 'a {
    fn construct(x: &'a i32) -> Self;
}

// A struct which implements this
#[derive(Debug)]
struct BorrowedI32<'a> {
    value: &'a i32
}
impl<'a> ConstructI32AsBorrowed<'a> for BorrowedI32<'a> {
    fn construct(value: &'a i32) -> Self { Self { value } }
}

// This is the important bit
// A trait which represents BorrowedValue as a String, say in some special way
// note that the type parameter BorrowedValue exists at the trait level, but the
// lifetime 'a exists at the method level
trait ShowBorrowedValue<BorrowedValue: std::fmt::Debug> {
    fn show_debug(&self, borrowed: BorrowedValue) -> String
    where BorrowedValue: for<'a> ConstructI32AsBorrowed<'a>;
}

// Define a simple struct which implements ShowBorrowedValue by capitalizing the debug outputs
struct ShowsI32InCapitals;
impl<BorrowedValue: std::fmt::Debug> ShowBorrowedValue<BorrowedValue> for ShowsI32InCapitals {
    fn show_debug(&self, borrowed: BorrowedValue) -> String
    where BorrowedValue: for<'a> ConstructI32AsBorrowed<'a>
    {
        format!("{:?}", borrowed).to_string().to_uppercase()
    }
}

pub fn main() {
    // We have a single instance of our struct
    let shows_i32_in_capitals = ShowsI32InCapitals;
    // But we want to apply it to two different borrowed values with two different lifetimes;
    // this checks that the `'a ` lifetime argument is not fixed at the level of the struct
    {
        let val_a = BorrowedI32::construct(&0_i32);
        shows_i32_in_capitals.show_debug(val_a);
    }
    {
        let val_b = BorrowedI32::construct(&1_i32);
        shows_i32_in_capitals.show_debug(val_b);
    }
}

我在这里试图告诉borrow 判断器的是,当我初始化show_i32_in_capitals时,我很乐意修复(更高级的)类型BorrowedValue -这不会改变.但是,我不想在这里修复生存期'a:我希望在调用show_debug时设置它.

目前,编译器给出了这个耐人寻味的错误:

error: implementation of `ConstructI32AsBorrowed` is not general enough
  --> src/main.rs:43:9
   |
43 |         shows_i32_in_capitals.show_debug(val_a);
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `ConstructI32AsBorrowed` is not general enough
   |
   = note: `ConstructI32AsBorrowed<'0>` would have to be implemented for the type `BorrowedI32<'_>`, for any lifetime `'0`...
   = note: ...but `ConstructI32AsBorrowed<'1>` is actually implemented for the type `BorrowedI32<'1>`, for some specific lifetime `'1

这意味着不知何故我的生命周期 不匹配.

推荐答案

Rust没有正确的HKT(可能永远不会有),但它们可以用Gats(泛型关联类型)来模拟,即使不方便:

#[derive(Debug)]
struct BorrowedI32<'a> {
    value: &'a i32
}
impl<'a> BorrowedI32<'a> {
    fn construct(value: &'a i32) -> Self { Self { value } }
}

trait BorrowedTypeConstructor {
    type Borrowed<'a>;
}

struct BorrowedI32TypeConstructor;
impl BorrowedTypeConstructor for BorrowedI32TypeConstructor {
    type Borrowed<'a> = BorrowedI32<'a>;
}

trait ShowBorrowedValue<BorrowedCtor: BorrowedTypeConstructor>
where
    for<'a> BorrowedCtor::Borrowed<'a>: std::fmt::Debug,
{
    fn show_debug(&self, borrowed: BorrowedCtor::Borrowed<'_>) -> String;
}

struct ShowsI32InCapitals;
impl<BorrowedCtor: BorrowedTypeConstructor> ShowBorrowedValue<BorrowedCtor> for ShowsI32InCapitals
where
    for<'a> BorrowedCtor::Borrowed<'a>: std::fmt::Debug,
{
    fn show_debug(&self, borrowed: BorrowedCtor::Borrowed<'_>) -> String {
        format!("{:?}", borrowed).to_string().to_uppercase()
    }
}

pub fn main() {
    let shows_i32_in_capitals = ShowsI32InCapitals;

    {
        let val_a = BorrowedI32::construct(&0_i32);
        let s = <ShowsI32InCapitals as ShowBorrowedValue<BorrowedI32TypeConstructor>>::show_debug(&shows_i32_in_capitals, val_a);
        println!("{s}");
    }
    {
        let val_b = BorrowedI32::construct(&1_i32);
        let s = <ShowsI32InCapitals as ShowBorrowedValue<BorrowedI32TypeConstructor>>::show_debug(&shows_i32_in_capitals, val_b);
        println!("{s}");
    }
}

Rust相关问答推荐

使用Rust s serde_json对混合数据类型进行优化'

如何将`Join_all``Vec<;Result<;Vec<;Foo&>;,Anywhere::Error&>;`合并到`Result<;Vec<;Foo&>;,Anywhere::Error&>;`

在执行其他工作的同时,从共享裁判后面的VEC中删除重复项

在跨平台应用程序中使用std::OS::Linux和std::OS::Windows

我应该将哪些文件放入我的GitHub存储库

异步函数返回的future 生存期

JSON5中的变量类型(serde)

对于rustc编译的RISC-V32IM二进制文件,llvm objdump没有输出

如何执行数组文字的编译时串联?

RUST 中的读写器锁定模式

仅发布工作区的二进制 crate

通过写入 std::io::stdout() 输出不可见

在描述棋盘时如何最好地使用特征与枚举

为什么Rust中无法推断生命周期?

当在lambda中通过引用传递时,为什么会出现终身/类型不匹配错误?

从 Axum IntoResponse 获取请求标头

在 Rust 中如何将值推送到枚举 struct 内的 vec?

如何在 Rust 中编写涉及异步的重试函数

如何获取包裹在 Arc<> 和 RwLock<> 中的 Rust HashMap<> 的长度?

为什么这个 Trait 无效?以及改用什么签名?