Изменчивость поля структуры в зависимости от изменчивости/владения переменной

просто наивный вопрос от новичка в Rust; как и следовало ожидать, это касается владения и изменчивости...

Проблема в следующем: у меня есть какая-то структура массива, которую я использую как прямоугольную матрицу.

struct Matrix {
    lines: usize,
    columns: usize,
    content: Vec<f32>,
}

Внутри одномерный массив content (с размером lines*columns) представляет всю прямоугольную матрицу m с m(i,j) = content[i*columns+j] для любых заданных i и j.

Из этой матрицы я хотел бы извлечь строку. Но по разным причинам я также хотел бы сохранить размер этой строки, т.е. количество столбцов матрицы (и, в конечном итоге, некоторую дополнительную информацию в целом).

Для этого я использую новый тип Line.

struct Line<'a> {
    columns: usize,
    content: &'a [f32],
}

Я предполагаю, что я использую срез для представления строки, так как это непрерывное пространство в памяти. Затем я могу реализовать функцию line() как таковую:

impl Matrix {
    fn line(&'a self, id: usize) -> Line<'a> {
        let realindex = id * self.columns;
        &self.content[realindex..realindex+self.columns]
    }
}

Но есть проблема: поле content в Line неизменяемо. Я могу изменить содержимое Line, надеясь, что это изменит содержимое матрицы владения.

В этом случае я думаю, что могу написать это, и это сработает:

struct Line<'a> {
    columns: usize,
    content: &'a mut [f32],
}

И я могу написать какую-нибудь line_mut функцию для получения этой структуры:

impl Matrix {
    fn line(&'a mut self, id: usize) -> Line<'a> {
        let realindex = id * self.columns;
        &mut self.content[realindex..realindex+self.columns]
    }
}

Но что произойдет, если я хочу просто получить неизменяемую строку из матрицы? С первой версией Line я не могу использовать line_mut и получить изменяемую строку; и наоборот, со второй версией Line я не могу использовать line и получить неизменяемую строку...

Вопрос в следующем: я что-то упускаю или так оно и есть? Другими словами, есть ли способ заставить Rust делать вывод об изменчивости некоторых полей структуры в соответствии с требуемой изменчивостью при использовании структуры? Что-то вроде этого:

let a : Line = ...; // type of content = &[f32]
let mut b : Line = ...; // type of = &mut [f32]

Если это так, что было бы хорошим решением для обеспечения доступности обеих функций (изменяемой строки и неизменяемой строки)? Два разных типа (например, ImmutLine и MutLine)?

Я также видел RefCell и внутреннюю изменчивость, но я не думаю, что это очень полезно в этом случае: во время компиляции я знаю, хочу ли я изменяемую или неизменяемую строку.


person Guillaume Dupont    schedule 26.04.2019    source источник
comment
Ваши рассуждения на самом деле довольно точны: получение &T или &mut T — очень важное различие. Обычное соглашение для геттеров и т.п. состоит в том, чтобы иметь два отдельных метода и вспомогательных типа. Соблюдение соглашений об именах: два метода line(...)/line_mut(...) и два типа Line/LineMut.   -  person E_net4 the curator    schedule 26.04.2019
comment
Я вижу, в конце концов, это имеет смысл в контексте системы типов Rust (очень своеобразной!) (как объяснено в ответе, который вы указали в своем первом комментарии). Это не кажется обычным, когда вы привыкли иметь много выводов, но также очень чисто в том, как четко демонстрирует, что изменчиво, а что нет.   -  person Guillaume Dupont    schedule 26.04.2019