среда, 3 февраля 2016 г.

Поля переменной величины внутри struct

Делаю хранилище данных на основе файла. У хранилища есть поле, которое содержит путь к файлу.

use std::path::Path;

pub struct Store {
    path: Path
}

impl Store {
   
    pub fn new(path: Path) -> Store {
        Store {
            path: path
        }
    }
}


Если указать тип поля std::path::Path, то выплывет непонятная ошибка:

error: the trait `core::marker::Sized` is not implemented for the type `[u8]` [E0277]

Хорошо, что в подробном описании присутствует строчка:

all local variables must have a statically known size

Значит, причина ошибки в том, что Rust не понимает, сколько памяти резервировать под нашу структуру, потому что путь к файлу может содержать разное количество символов.

Что делать? Поле должно хранить указатель. Размер указателя на переменную Rast'у известен.

use std::path::Path;

pub struct Store {
    path: &Path
}

impl Store {
   
    pub fn new(path: &Path) -> Store {
        Store {
            path: path
        }
    }
}

Прежняя ошибка, действительно, пропала. Появилась новая:

error: missing lifetime specifier [E0106]

Она относится к определению поля стуктуры:

 pub struct Store {
    path: &Path
}


Да, язык программирования накладывает требование явно указывать время жизни, ести структура содержит указатели:

You’ll also need explicit lifetimes when working with structs that contain references

Доработаем код, с учётом этого обстоятельства.

use std::path::Path;

pub struct Store<'a> {
    path: &'a Path
}

impl Store {
   
    pub fn new(path: &Path) -> Store {
        Store {
            path: path
        }
    }
}

Ошибка пропала. Возникает однако другая проблема:

error: wrong number of lifetime parameters: expected 1, found 0 [E0107]

Неверно записано название структуры в блоке с методами:

impl Store {

Исправляем:

use std::path::Path;

pub struct Store<'a> {
    path: &'a Path
}

impl Store<'a> {
   
    pub fn new(path: &Path) -> Store {
        Store {
            path: path
        }
    }
}


Проблема решена. Появляется следующее препятствие:

error: use of undeclared lifetime name `'a` [E0261]

Оказывается, прежде чем использовать имя жизни, его нужно объявить сразу позади слова impl (см. документацию). Новый вариант кода выглядит теперь так:

use std::path::Path;

pub struct Store<'a> {
    path: &'a Path
}

impl<'a> Store<'a> {
   
    pub fn new(path: &Path) -> Store {
        Store {
            path: path
        }
    }
}

Ещё одна ошибка ушла. Мы продвинулись вперёд, однако работа не закончена. Видим следующую ошибку:

error: wrong number of lifetime parameters: expected 1, found 0 [E0107]

Статический метод new возвращает тип Store без указания времён жизни. Исправляем:

use std::path::Path;

pub struct Store<'a> {
    path: &'a Path
}

impl<'a> Store<'a> {
   
    pub fn new(path: &Path) -> Store<'a> {
        Store {
            path: path
        }
    }
}

Движемся дальше. Следующая ошибка относится к типу параметра метода new:

error: cannot infer an appropriate lifetime for automatic coercion due to conflicting requirements [E0495]

Добавляем время жизни в определение типа параметра path:

use std::path::Path;

pub struct Store<'a> {
    path: &'a Path
}

impl<'a> Store<'a> {
   
    pub fn new(path: &'a Path) -> Store<'a> {
        Store {
            path: path
        }
    }
}


Похоже, этот код работает. Конечно, время жизни пути к файлу должно совпадать со временем жизни экземпляра хранилища. Ошибок больше нет. Версия Rust 1.6




Комментариев нет:

Отправить комментарий