Rust 为什么生锈会';在类型构造函数中是否强制可变引用为不可变引用?
可以将Rust 为什么生锈会';在类型构造函数中是否强制可变引用为不可变引用?,rust,immutability,coercion,type-constructor,Rust,Immutability,Coercion,Type Constructor,可以将&mut T T强制为&T,但如果类型构造函数中发生类型不匹配,则此操作无效 使用ndarray::*;//0.13.0 fn打印(a:&阵列视图1){ println!(“{:?}”,a); } pub-fn测试(){ 设mut x=array![1i32,2,3]; 打印(&x.view_mut()); } 对于上述代码,我得到以下错误: | 9 | print(&x.view_mut()); | ^^^^^^^^^^^^^ types
&mut T T
强制为&T
,但如果类型构造函数中发生类型不匹配,则此操作无效
使用ndarray::*;//0.13.0
fn打印(a:&阵列视图1){
println!(“{:?}”,a);
}
pub-fn测试(){
设mut x=array![1i32,2,3];
打印(&x.view_mut());
}
对于上述代码,我得到以下错误:
|
9 | print(&x.view_mut());
| ^^^^^^^^^^^^^ types differ in mutability
|
= note: expected reference `&ndarray::ArrayBase<ndarray::ViewRepr<&i32>, ndarray::dimension::dim::Dim<[usize; 1]>>`
found reference `&ndarray::ArrayBase<ndarray::ViewRepr<&mut i32>, ndarray::dimension::dim::Dim<[usize; 1]>>`
|
9 |打印(&x.视图_mut());
|^^^^^^^^^^^^^^^^^^^类型的可变性不同
|
=注意:应为引用“%ndarray::ArrayBase”`
找到引用“%ndarray::ArrayBase”`
强制
&mut i32
到&i32
是安全的,那么为什么不在这种情况下应用它呢?您能否提供一些关于它如何可能适得其反的示例?请考虑检查依赖于内容的空字符串在is_empty
函数运行时保持不变(仅用于说明,请勿在生产代码中使用此选项):
struct容器{
内容:T
}
impl容器{
fn新(内容:T)->Self
{
自我{内容}
}
}
恳求{
fn为空(&self,s:&str)->bool
{
设str=format!(“{}{}”,self.content,s);
&str==s
}
}
fn main(){
让mut foo:String=“foo.”to_owned();
let container:container=container::new(&mut-foo);
std::thread::spawn(| |{
container.content.replace_范围(1..2,“”);
});
println!(“一个空str实际上是空的:{}”,container.is_empty(“”)
}
由于&mut String
不会强制转换为&String
,因此此代码不会编译。但是,如果是这样,那么新创建的线程可能会在格式之后更改内容
调用,但在is _empty
函数中的相等比较之前,从而使容器内容不可变的假设无效,这是空检查所必需的。一般来说,将类型
强制为类型
是不安全的
例如,考虑这个包装器类型,它在没有任何不安全代码的情况下实现,因此声音:
#[派生(复制、克隆)]
结构包装器(T);
包装器的impl-Deref{
类型Target=T::Target;
fn deref(&self)->&T::Target{&self.0}
}
包装器的impl-DerefMut{
fn deref_mut(&mut self)->&mut T T::Target{&mut self.0}
}
此类型具有以下属性:&Wrapper
自动取消对&T
的引用,&mut-Wrapper
自动取消对&mut-T
的引用。此外,Wrapper
如果T
是可复制的
假设存在一个函数,该函数可以接受一个&包装器
,并将其强制为一个&包装器
:
fn降级\u包装\u参考(w:&'a wrapper我想我已经知道了。如果我直接对字符串做同样的操作,我会得到不能将foo作为不可变的借来,因为它也是作为可变的
借来的。另一方面,容器
总是通过不可变的引用传递,而不管内容
类型如何,所以这个机制不会被触发。不要如果没有安全锈迹中的包装器,我们是否也会遇到同样的情况?@pkubik我想这是一个不错的反例,我的代码应该更加明确,但是如果你在println!
语句中添加类型注释,你的示例中会出现一个终生错误,而我的示例中不会。比较(更新、编译)与(已更新,不编译)。我将更新我的答案以包含此内容。(我猜问题在于它没有被用作可变引用,因此它实际上不会检查它是否确实是可变的。添加显式类型注释将确保可变引用以可变方式使用,这将导致终身错误,但不会。)是的,这实际上很有趣,编译器没有将引用变量的定义视为借用,您必须实际使用它来导致错误。我想它在组织代码时提供了更多的灵活性。
|
9 | print(&x.view_mut());
| ^^^^^^^^^^^^^ types differ in mutability
|
= note: expected reference `&ndarray::ArrayBase<ndarray::ViewRepr<&i32>, ndarray::dimension::dim::Dim<[usize; 1]>>`
found reference `&ndarray::ArrayBase<ndarray::ViewRepr<&mut i32>, ndarray::dimension::dim::Dim<[usize; 1]>>`
struct Container<T> {
content: T
}
impl<T> Container<T> {
fn new(content: T) -> Self
{
Self { content }
}
}
impl<'a> Container<&'a String> {
fn is_empty(&self, s: &str) -> bool
{
let str = format!("{}{}", self.content, s);
&str == s
}
}
fn main() {
let mut foo : String = "foo".to_owned();
let container : Container<&mut String> = Container::new(&mut foo);
std::thread::spawn(|| {
container.content.replace_range(1..2, "");
});
println!("an empty str is actually empty: {}", container.is_empty(""))
}