Почему [u8] не реализует Clone?

avatar
Guerlando OCs
1 июля 2021 в 19:13
286
2
2

Приведенный ниже пример является просто примером, я знаю, что мне не нужен клон, чтобы это работало, но если бы S было перечислением с [T] и Vec<T> и я хотел бы изменить размер вектора, T должно быть Clone.

struct S<'a, T>{
    a: &'a [T]
}

impl<'a, T> S<'a, T> {
    pub fn borrow(&self) -> &[T] 
    where [T]: Clone {
        self.a
    }
}

fn main() {
    let slice:[u8;3] = [1,2,3]; 
    let x = S{a: &slice};
    x.borrow();
}

Детская площадка

Ошибка:

error[E0277]: the trait bound `[u8]: Clone` is not satisfied
  --> src/main.rs:17:7
   |
17 |     x.borrow();
   |       ^^^^^^ the trait `Clone` is not implemented for `[u8]`

Итак, почему не [u8] Clone?

Источник
EvilTak
1 июля 2021 в 19:34
5

[T] является типом без размера и, следовательно, не может быть Cloned (обратите внимание, что Clone::clone возвращает Self, но [T] не может находиться в стеке). Однако Box<[T]> действительно реализует Clone if T: Clone, потому что он живет в куче.

Ответы (2)

avatar
Peter Hall
1 июля 2021 в 20:44
6

Так почему же [u8] Clone?

Посмотрите на тип метода clone в определении Clone:

pub trait Clone {
    pub fn clone(&self) -> Self;
    // more stuff omitted..
}

Он возвращает Self, что в данном случае будет [u8]. Проблема в том, что [u8] не Sized, то есть, поскольку мы не знаем, сколько элементов он будет иметь, мы не можем знать его размер во время компиляции. Но возврат его из этого метода будет означать, что он перемещен в стек, что невозможно, если компилятор не знает, сколько места для него оставить.

effect
1 июля 2021 в 20:50
0

Возможное исправление состоит в том, чтобы использовать константные дженерики и использовать шаблонный массив фиксированного размера вместо среза?

Peter Hall
1 июля 2021 в 21:10
0

Я действительно не понимаю, чего вы пытаетесь достичь, поэтому трудно предложить «исправление». Как вы говорите, пример не сообщает о проблеме, потому что Clone не нужен. На первый взгляд кажется, что вам нужно T: Clone, а не [T]: Clone, но вы не предоставили достаточно информации, чтобы утверждать это с уверенностью.

avatar
egerhard
1 июля 2021 в 19:34
2

Мне удалось скомпилировать ваш код, добавив & в предложение where:

impl<'a, T> S<'a, T> {
    pub fn borrow(&self) -> &[T]
    where
        &'a [T]: Clone,
    {
        self.a
    }
}

Ключ здесь в том, что срез является ссылкой на непрерывный набор значений: &[u32].

Что касается того, почему [u32] не реализует Clone: я полагаю, что причина в том, что у него нет никакой информации о том, сколько элементов находится в диапазоне памяти. Принимая во внимание, что тип среза &[u32] содержит ссылку на начало последовательности значений u32 в памяти и на количество элементов. Без количества элементов клонирование данных было бы невозможно.

EvilTak
1 июля 2021 в 19:43
1

Обратите внимание, что &'a [T]: Clone может не привести к желаемому поведению, так как накладывает ограничение Clone на тип reference &[T]. Неизменяемые ссылки всегда CloneCopy) -- &[T] : Clone не обязательно означает, что сам фрагмент может быть клонирован.

EvilTak
1 июля 2021 в 19:56
1

Пример: Вызов self.a.clone() в S::borrow на самом деле не клонирует срез или его составляющие — он только клонирует ссылку.

egerhard
2 июля 2021 в 17:34
0

Это очень хороший момент, и это полезно знать.