gpt4 book ai didi

rust - 我需要任何 *variantType 标记吗?

转载 作者:行者123 更新时间:2023-11-29 08:19:34 24 4
gpt4 key购买 nike

我正在尝试通过 Rust 以类型安全的方式与类型不安全的 C 库进行交互。 C 接口(interface)处理一些void 指针。具体来说,有一个 write 和一个 read 函数,它们将这样一个 void 指针作为参数并做一些显而易见的事情(将给定的数据写入其他地方或从那个地方读入给定的缓冲区)。这是什么类型的数据,是早先约定的 py 将某个整数值赋给 open 函数

1 = float
2 = int32_t
4 = int16_t
etc...

我用像这样的参数化 Rust 结构表示一个打开的输出流(用户可以在其中调用 write on):

pub struct OutputStream<T> {
c_stream: *mut ()
}

impl<T: ValueType> for OutputStream<T> {
pub fn write(&mut self, data: &[T]) -> Result<(),SomeErrorType> {
unsafe { ... }
}
}

其中 ValueType 是我为所有支持的值类型编写的特征,其他人无法实现它(私有(private)基础特征技巧)。因此,显然 T 在结构中的任何地方都没有提到。这似乎是 ContravariantType 的情况标记。但我真的不明白这些类型标记。访问有关差异的维基百科页面没有帮助。我只是看不出方差与它如何应用于 Rust 的类型参数之间的联系。而且我真的不知道这种标记实际上会阻止什么。

所以我的问题是:我的 OutputStream 是否需要这些标记之一?如果有,是哪一个,为什么?使用它到底能防止什么? InputStream 也是如此,它提供了 read 方法而不是 write 方法。

最佳答案

一般来说,方差决定了参数化类型之间关于参数的子类型关系:

Covariance:      T <: U    =>    F[T] <: F[U]
Contravariance: T <: U => F[U] <: F[T]
Invariance: T <: U => neither of the above
Bivariance: T <: U => both of the above

你的类型自然逆变的:它的方法只消费T类型的值,但不生产他们;这就是所谓的消费者类型。然而,Rust 中的子类型非常有限;据我所知,唯一允许任何类型的子类型关系的类型是引用(例如,您可以将 &'static str 传递到 &'a str 变量中,因为'static 生命周期大于或等于任何其他生命周期,因此 &'static str&'a str 的子类型,对于任何 'a).

所以,如果我没理解错的话,你确实需要方差注释。如果您的 T 参数可以作为引用,请使用 ContravariantType,这样您就可以这样做:

fn push_something_to(os: OutputStream<&'static str>) { ... }

let s: OutputStream<&'a str> = ...; // and 'a is less than 'static
push_something_to(s); // this is safe to do because &'static str is valid &'a str

但不能这样做:

let s: OutputStream<int> = ...;
push_something_to(s); // oops, push_something_to expects stream of &'static str

InvariantType 两者都被禁止。


但是,我这边似乎存在一些深刻的误解,因为关于方差标记的文档中的代码和我自己的代码都不适合我当前的 Rust:

use std::ptr;
use std::mem;

struct S<T> { x: *const () }

fn get<T>(s: &S<T>, v: T) {
unsafe {
let x: fn(T) = mem::transmute(s.x);
x(v)
}
}

fn main() {
let s: S<int> = S { x: ptr::null() };
get::<Box<int>>(&s, box 1);
}

根据文档,由于默认情况下参数化类型是双变的,这应该可以编译,但事实并非如此:它表现得好像参数是不变的。

这是我自己的例子:

#![allow(dead_code)]

type F<T> = fn(T);

fn test_1<'a>(f: F<&'a str>) -> F<&'static str> {
f
}

struct S<T> {
_m: std::kinds::marker::ContravariantType<T>
}

fn test_2<'a>(s: S<&'a str>) -> S<&'static str> {
s
}

fn main() {}

据我所知,这个程序应该可以编译,但它没有:

<anon>:9:5: 9:6 error: mismatched types: expected `S<&'static str>` but found `S<&'a str>` (lifetime mismatch)
<anon>:9 s
^
<anon>:8:47: 10:2 note: the lifetime 'a as defined on the block at 8:46...
<anon>:8 fn test<'a>(s: S<&'a str>) -> S<&'static str> {
<anon>:9 s
<anon>:10 }
note: ...does not necessarily outlive the static lifetime

如果我删除 Stest_2,它编译得很好,证明函数类型确实是关于它们的参数类型的逆变。

我不知道发生了什么,看起来它值得另一个问题。

关于rust - 我需要任何 *variantType 标记吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25365383/

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