&T字面上是Slice的别名吗?

Dou*_*oug 10 rust

&[T] 令我困惑.

我天真地认为像&T,&[T]是一个指针,这就是说,一个数字指针地址.

但是,我已经看到了一些像这样的代码,我看到工作正常(为了演示目的而简化;但是你在许多'as_slice()'实现中看到这样的代码)我感到非常惊讶:

extern crate core;
extern crate collections;

use self::collections::str::raw::from_utf8;
use self::core::raw::Slice;
use std::mem::transmute;

fn main() {
  let val = "Hello World";
  {
    let value:&str;
    {
      let bytes = val.as_bytes();
      let mut slice = Slice { data: &bytes[0] as *const u8, len: bytes.len() };
      unsafe {
        let array:&[u8] = transmute(slice);
        value = from_utf8(array);
      }
      // slice.len = 0;
    }
    println!("{}", value);
  }
}
Run Code Online (Sandbox Code Playgroud)

所以.

我最初认为这是无效的代码.

也就是说,在Slice块作用域内创建的实例将返回到块作用域之外(通过转换),尽管代码运行,但println!实际上是通过不安全指针访问不再有效的数据.坏!

......但似乎并非如此.

考虑评论该行 // slice.len = 0;

发生这种情况时,此代码仍可正常运行(打印"Hello World").

这条线......

value = from_utf8(array);
Run Code Online (Sandbox Code Playgroud)

如果它是一个指向'slice'变量的无效指针,则lenprintln()语句将为0,但事实并非如此.因此,不仅是指针值的副本,而且是Slice结构的完整副本.

是对的吗?

这是否意味着一般来说&[T]只要实际的内部数据指针有效就返回一个有效的,无论&[T]返回的原始范围如何,因为&[T]赋值是一个复制操作?

(对我而言,这似乎是非常反直觉的......所以我可能会误解;如果我是对的,&[T]那么指向相同数据的那两个就无法生效,因为如果修改一个数据,它们将无法同步...)

Vla*_*eev 14

&[T]正如您所注意到的,切片与结构"等效" std::raw::Slice.实际上,它是值Slice的内部表示&[T],是的,它是指针和指针后面的数据长度.有时这种结构称为"胖指针",即指针和附加信息.

当您传递&[T]值时,您确实只是复制其内容 - 指针和长度.

如果它是指向'slice'变量的无效指针,则pr​​intln()语句中的len将为0,但实际上不是.因此,不仅是指针值的副本,而且是Slice结构的完整副本.是对的吗?

所以,是的,确切地说.

这是否意味着通常只要实际的内部数据指针有效,它就会返回&[T],无论原始&[T]的返回范围是什么,因为&[T]赋值是复制操作?

这也是事实.这是借来的引用的整个想法,包括切片 - 借用的引用被静态检查,只要它们的指示对象存在就被使用.当DST最终落地时,切片和常规参考将更加统一.

(对我而言,这似乎是非常反直觉的......所以我可能会误解;如果我是对的,那么两个&[T]指向相同的数据是无效的,因为它们不会同步长度如果你修改一个...)

这实际上是一个绝对有效的问题; 这是别名的问题之一.但是,Rust的设计正是为了防止此类错误.有两种方法可以使切片的别名有效.

首先,切片不能改变长度; 没有定义的方法&[T]可以让你改变它的长度.您可以从切片创建派生切片,但它将是一个新对象.

但即使切片不能改变长度,如果数据可以通过它们进行变异,如果别名也会带来灾难.例如,如果slice中的值是枚举实例,则改变此类别名切片中的值可能会使指向此切片中包含的枚举值的内部的指针无效.所以,第二,Rust别名slice(&[T])是不可变的.您无法更改其中包含的值,也无法将可变引用添加到其中.

这两个功能(以及编译器检查生命周期)使切片的别名绝对安全.但是,有时您需要修改切片中的数据.然后你需要可变片,称为&mut [T].您可以通过这样的切片更改数据; 但这些切片不是别的.您不能在同一个结构(例如数组)中创建两个可变切片,因此您不能做任何危险的事情.

但是,请注意,使用transmute()将切片转换为a Slice或反之亦然是一种不安全的操作.&[T]如果你使用正确的方法创建它是静态的保证是正确的,例如调用as_slice()a Vec.但是,使用Slicestruct 手动创建它然后将其转换&[T]为容易出错并且可以轻松地对程序进行分段,例如,当您为其分配的长度超过实际分配的长度时.