如何在Rust中实际使用动态大小的类型?
理论上,动态大小的类型(DST)已经登陆,我们现在应该能够使用动态大小的类型实例。实际上,我既不能让它工作,也不能理解它周围的测试 一切似乎都围绕着如何在Rust中实际使用动态大小的类型?,rust,Rust,理论上,动态大小的类型(DST)已经登陆,我们现在应该能够使用动态大小的类型实例。实际上,我既不能让它工作,也不能理解它周围的测试 一切似乎都围绕着大小?关键字。。。但你到底是如何使用它的呢 我可以把一些类型放在一起: // Note that this code example predates Rust 1.0 // and is no longer syntactically valid trait Foo for Sized? { fn foo(&self) ->
大小?
关键字。。。但你到底是如何使用它的呢
我可以把一些类型放在一起:
// Note that this code example predates Rust 1.0
// and is no longer syntactically valid
trait Foo for Sized? {
fn foo(&self) -> u32;
}
struct Bar;
struct Bar2;
impl Foo for Bar { fn foo(&self) -> u32 { return 9u32; }}
impl Foo for Bar2 { fn foo(&self) -> u32 { return 10u32; }}
struct HasFoo<Sized? X> {
pub f:X
}
我大致上理解,你不能有一个裸动态大小的类型;您只能通过指针与其中一个进行交互,但我不知道如何进行交互。免责声明:这些只是我做的几个实验的结果,再加上我的测试 DST是编译时不一定知道大小的类型 在DST之前 像
[i32]
这样的切片或像IntoIterator
这样的裸特征不是有效的对象类型,因为它们没有已知的大小
结构可以如下所示:
// [i32; 2] is a fixed-sized vector with 2 i32 elements
struct Foo {
f: [i32; 2],
}
// & is basically a pointer.
// The compiler always knows the size of a
// pointer on a specific architecture, so whatever
// size the [i32] has, its address (the pointer) is
// a statically-sized type too
struct Foo2<'a> {
f: &'a [i32],
}
// f is (statically) unsized, so Foo is unsized too
struct Foo {
f: [i32],
}
或者像这样:
// [i32; 2] is a fixed-sized vector with 2 i32 elements
struct Foo {
f: [i32; 2],
}
// & is basically a pointer.
// The compiler always knows the size of a
// pointer on a specific architecture, so whatever
// size the [i32] has, its address (the pointer) is
// a statically-sized type too
struct Foo2<'a> {
f: &'a [i32],
}
// f is (statically) unsized, so Foo is unsized too
struct Foo {
f: [i32],
}
枚举和元组也是如此
使用DST
您可以声明一个结构(或枚举或元组),如上面的Foo
,其中包含一个未调整大小的类型。包含未调整大小的类型的类型也将不调整大小
虽然定义Foo
很容易,但是创建Foo
的实例仍然很难,而且可能会发生变化。由于从技术上讲,您无法根据定义创建未调整大小的类型,因此必须创建Foo
的大小对应项。例如,Foo{f:[1,2,3]}
,一个Foo
,它有一个静态已知的大小,并对一些管道进行编码,以让编译器知道如何将其强制为其静态非大小的对应项Foo
。从Rust 1.5开始,在安全和稳定的Rust中执行此操作的方法仍在研究中(有关更多信息,请参阅)
幸运的是,除非您正在创建一种新类型的智能指针(如Rc
),否则您不太可能定义一个新的DST,这应该是非常罕见的
想象一下,Rc
的定义与上面的Foo
类似。由于它具有所有管道来执行从大小到非大小的强制,因此可以使用它来执行以下操作:
use std::rc::Rc;
trait Foo {
fn foo(&self) {
println!("foo")
}
}
struct Bar;
impl Foo for Bar {}
fn main() {
let data: Rc<Foo> = Rc::new(Bar);
// we're creating a statically typed version of Bar
// and coercing it (the :Rc<Foo> on the left-end side)
// to as unsized bare trait counterpart.
// Rc<Foo> is a trait object, so it has no statically
// known size
data.foo();
}
我们想为实现显示的所有包装的T
定义一个覆盖impl
impl<'a, T> Print for FooSized<'a, T>
where
T: 'a + fmt::Display,
{
fn print(&self) {
println!("{}", self.0)
}
}
嗯。。。这很尴尬。。。幸运的是,我们有一种方法可以将结构泛化为直接使用str
(以及一般的非大小化类型):?大小化的
//same as before, only added the ?Sized bound
struct Foo<'a, T: ?Sized>(&'a T)
where
T: 'a;
impl<'a, T: ?Sized> Print for Foo<'a, T>
where
T: 'a + fmt::Display,
{
fn print(&self) {
println!("{}", self.0)
}
}
对于一个不太做作(但简单)的实际示例,您可以查看标准库中的trait
回到你的问题上来
大小为的语法现在已过时。它过去指的是Self
的类型,声明“Foo”可以由非大小的类型实现,但现在这是默认值。现在,任何特征都可以用于非大小的类型,即,您现在可以拥有:
trait Foo {
fn foo(&self) -> i32;
}
//[i32] is unsized, but the compiler does not complain for this impl
impl Foo for [i32] {
fn foo(&self) -> i32 {
5
}
}
如果您不希望您的trait可用于未调整大小的类型,您可以使用size
绑定:
// now the impl Foo for [i32] is illegal
trait Foo: Sized {
fn foo(&self) -> i32;
}
目前,要创建一个HasFoo
来存储一个已擦除的Foo
类型,您需要首先创建一个具有固定具体类型的类型,然后强制将指向它的指针指向DST表单,即
let has_too: &HasFoo<Foo> = &HasFoo { f: Bar };
let has_too:&HasFoo=&HasFoo{f:Bar};
调用具有\u foo.f.foo()
在将来,这些DST强制转换几乎肯定可以使用as
,但目前需要通过显式类型提示进行强制。要修改,这里有一种使用属性的不同方式来看待它
struct Foo<'a, T>
where
T: 'a + ?Sized,
{
printable_object: &'a T,
}
impl<'a, T> Print for Foo<'a, T>
where
T: 'a + ?Sized + fmt::Display,
{
fn print(&self) {
println!("{}", self.printable_object);
}
}
fn main() {
let h = Foo {
printable_object: "hello",
};
h.print();
}
struct Foo Print for Foo下面是一个基于的完整示例。重要的技巧是将要包含DST的类型设置为不需要调整泛型大小的泛型类型(通过?调整大小
)。然后可以使用Bar1
或Bar2
构造一个具体值,然后立即将其转换
结构HasFoo(F);
impl HasFoo{
fn使用信息技术(&self){
println!(“{}”,self.0.foo())
}
}
fn main(){
//同样可以使用“&HasFoo”或“Rc”等。
让ex1:Box=Box::new(HasFoo(Bar1));
设ex2:Box=Box::new(HasFoo(Bar2));
例1.使用_it();
ex2.使用_it();
}
特色食品{
fn foo(&self)->u32;
}
结构Bar1;
Bar1的impl Foo{
fn foo(和self)->u32{
9
}
}
结构Bar2;
Bar2的impl Foo{
fn foo(和self)->u32{
10
}
}
您应该包括与您发布的任何错误消息相对应的代码。您确定DST真的已经登陆了吗?我想在这种情况下,应该会有一个适当的宣布。并且还没有关闭。@VladimirMatveev:IIRC,它的实现是不完整的,并且是在一个功能门后面。我在测试中没有看到功能门,DST似乎在工作,但在当前未完成的状态下还没有发挥应有的作用(如@VladimirMatveev提供的链接中所述)。请参阅useHi@Paolo的示例,感谢您的示例,有一点我无法跟上。//未编译。“hello”是一个&'static str,所以self print是str/(没有大小)让h_s=FooSized(“hello”)代码>原因FooSized
定义为:structFooSized@RyanLe因为T
没有大小(正如您所说,它是str
)。在DST之前,您无法表示该绑定,因为str
本身不能用作类型。即使在DST之后,您也不能直接使用str
,它始终需要在指针后面,这样就不会发生变化。@PaoloFalabella为了避免混淆,我建议您在这里更正您的短语:“您表达这一点的方式是通过?size”边界“?”在某些方面与界限相反;它实际上说T可以是大小的也可以是非大小的,因此它拓宽了我们可以使用的可能类型,而不是像边界通常那样限制它们。。。它实际上说T可能实现也可能不实现?size
trait,因此它拓宽了可能的类型w
struct Foo<'a, T>
where
T: 'a + ?Sized,
{
printable_object: &'a T,
}
impl<'a, T> Print for Foo<'a, T>
where
T: 'a + ?Sized + fmt::Display,
{
fn print(&self) {
println!("{}", self.printable_object);
}
}
fn main() {
let h = Foo {
printable_object: "hello",
};
h.print();
}