2015-06-15 2 views
0

До сегодняшнего дня, я думал, объявив переменную без mut, убедитесь, что она не может быть изменена после инициализации.Есть ли способ объявить переменную неизменной значимым образом?

Я думал, что это здорово, потому что я всегда возмущался тем, что const в C и C++ ничего не гарантировал.

Я только что узнал, что я ошибся: ржавчина допускает внутреннюю изменчивость (см. std::cell). Это дает вам некоторые гарантии, но не то, что я ожидаю и желаю, когда я услышу непреложный.

Есть ли способ объявить что-то «действительно неизменным»?

+3

Вы всегда можете использовать небезопасный код, чтобы разорвать любую гарантию неизменности, нет никакого способа обойти это ... –

+0

Если вы не хотите внутренней изменчивости, а что просто не использовать типы, которые ее предоставляют? – Levans

+0

@ Levans это может быть не так тривиально, возможно, тип, который вы используете, является общим, и пользователь может подключить тип с внутренней изменчивостью. Или вы используете тип, в котором есть частное поле с внутренней изменчивостью ... Вы, возможно, никогда не узнаете об этом ... –

ответ

3

Предотвращение внутренней изменчивости невозможно во время исполнения кода (постоянная оценка делает это легко, никакой мутации не существует). Любой тип, который вы используете, у которого нет контроля, может использовать небезопасный код для достижения внутренней изменчивости. Чтобы предотвратить наиболее распространенные случаи, вы можете использовать так называемую «маркерную черту». Эта черта не имеет других целей, но позволяет вам различать типы, которые реализуют вашу черту и типы, которые этого не делают.

#![feature(optin_builtin_traits)] 

use std::cell::{RefCell, Cell, UnsafeCell}; 
use std::sync::Mutex; 

unsafe trait ReallyImmutable {} 

unsafe impl ReallyImmutable for .. {} 
impl<T> !ReallyImmutable for RefCell<T> {} 
impl<T> !ReallyImmutable for Cell<T> {} 
impl<T> !ReallyImmutable for UnsafeCell<T> {} 
impl<T> !ReallyImmutable for Mutex<T> {} 
impl<'a, T> !ReallyImmutable for &'a mut T {} 
impl<T> !ReallyImmutable for *mut T {} 
impl<T> !ReallyImmutable for *const T {} 

Это, конечно, недостаток, требующая от вас черного списка интерьера переменчивости вместо белого перечня неизменяемых типов. Так что вы всегда можете чего-то пропустить.

+0

И есть тот факт, что вы можете преобразовать '* const T' в' * mut T', а затем изменить его таким образом.^_^ – Shepmaster

+1

как я уже сказал ...это не белый список, а в ситуациях с небезопасным кодом все равно не имеет значения, поэтому использование '* mut T' уже требует небезопасных ... но да ... Я пропустил этот тривиальный элемент ^^ ... и вы можете перейти от '& T' в' * const T', а затем мы вернулись туда, где мы начали ... xD –

+0

О, я не пытаюсь каким-либо образом аннулировать ваш ответ, просто указывая примеры того, как вредоносный конечный пользователь может подорвать это, как вы уже говорили, было возможно. – Shepmaster

Смежные вопросы