电子商务网站开发项目设计报告,昆山市做网站的公司,注册网站在哪里创建,微信公众号私自建设电影网站目录
1、引用与借用 1.1 可变引用
1.2 悬垂引用
1.3 引用的规则
2、slice 类型 2.1 字符串字面量其实就是一个slice
2.2 总结 1、引用与借用
在之前我们将String 类型的值返回给调用函数#xff0c;这样会导致这个String会被移动到函数中#xff0c;这样在原来的作用域…目录
1、引用与借用 1.1 可变引用
1.2 悬垂引用
1.3 引用的规则
2、slice 类型 2.1 字符串字面量其实就是一个slice
2.2 总结 1、引用与借用
在之前我们将String 类型的值返回给调用函数这样会导致这个String会被移动到函数中这样在原来的作用域不可访问了但是我们功能一个String值得引用这样就不会导致这个String类型的值被移动而传递的只是一个引用。引用更像一个指针因为是一个地址我们就可以基于这个地址找到改地址上存储的数据。 与指针不同引用确保指向某个特定类型的有效值。
下面是一个引用传递的示例
fn main() {let str String::from(hello world!);let len _length(str);println!(str is value: {}, str);println!(str length is: {}, len)
}
fn _length(s: String) -usize {s.len()
} 运行结果所示所示 根据以上代码可以看出_length方法中传递的参数为str所以这里传递的是str值的引用用符号代表引用 以下是一张对应的示意图 根据上图也能看出s是s1的引用引用的是s1在堆中对应类型的值。 注意与使用 引用相反的操作是 解引用dereferencing它使用解引用运算符*。 变量 s 有效的作用域与函数参数的作用域一样不过当 s 停止使用时并不丢弃引用指向的数据因为 s 并没有所有权。当函数使用引用而不是实际值作为参数无需返回值来交还所有权因为就不曾拥有所有权。
我们将创建一个引用的行为称为 借用borrowing因为我们并没有拥有它的所有权只是暂时借用以下。
我们可以尝试修改一下引用把引用值改了看下是否可以这就类似于我借了别人的东西然后把东西换了个样子看看是不是可以呢
fn main() {let str String::from(hello world!);let len _length(str);println!(str is value: {}, str);
}
fn _length(s: String) {s.push_str(我把你给改了..........);
}
运行一下看下结果 根据提示可以s是一个引用因此它引用的数据不能作为可变数据借用。 1.1 可变引用
允许我们修改一个借用的值这就是 可变引用把上面的示例改一下如下所示:
fn main() {let mut str String::from(hello world!);_length(mut str);println!(str is value: {}, str);
}
fn _length(s: mut String) {s.push_str(我把你给改了..........);
}
运行代码再看一下结果 首先定义str必须时可变的在方法中传递参数也要指定引用为可变引用因为引用指向的是被引用的地址所以就会改变原有的值。 注意可变引用有一个很大的限制如果你有一个对该变量的可变引用你就不能再创建对该变量的引用。 看以下示例
fn main() {let mut str String::from(hello world!);let a mut str;let b mut str;println!(a {}, b{}, a, b)
} 根据错误提示可以知道同一时间不能多次借用str作为可变变量。Rust这样限制是因为可以在编译时就避免数据竞争。数据竞争data race类似于竞态条件它可由这三个行为造成
两个或更多指针同时访问同一数据。至少有一个指针被用来写入数据。没有同步数据访问的机制。
再看下以下示例
fn main() {let mut str String::from(hello world!);let c mut str;let b str;println!(b{} {}, b, c)
} 也会报错借用和可变借用不能同时被使用。 再看下一个示例
fn main() {let mut str String::from(hello world!);let c mut str;println!({}, c);let b str;println!({}, b)
} 可以看到这次是可以打印处结果的在第一次打印的时候变量的作用域也就结束了因而在下次进行赋值时可以的。
1.2 悬垂引用
在具有指针的语言中很容易通过释放内存时保留指向它的指针而错误地生成一个 悬垂指针dangling pointer所谓悬垂指针是其指向的内存可能已经被分配给其它持有者。相比之下在 Rust 中编译器确保引用永远也不会变成悬垂状态当你拥有一些数据的引用编译器确保数据不会在其引用之前离开作用域。
下面时一个悬垂应用的示例
fn main() {dp();
}
fn dp() - String { // 返回字符串的引用let str String::from(hello world!); // 创建一个字符串str // 返回字符串的引用
} // str 的作用域结束
// 方法返回的时字符串的引用而字符串离开作用与被释放然在此返回该字符串的引用
// 就会导致返回的结果不是预期的结果在Rust中是不让这样操作的。 直接运行会报如下错误 根据报错可知此函数的返回类型包含借用值但没有可供借用的值在返回类型引用处提示 错误的声明周期修饰符。 我们改以下返回字符串本身看一下结果怎么样
fn main() {println!(value is {}, dp())
}
fn dp() - String { let str String::from(hello world!); return str
}
运行一下看看 发现对应的值给打印出来所有权交出去了所以可打印出对应的值。
1.3 引用的规则
根据之前的结果我们可以总结出以下两点
在任意给定时间要么 只能有一个可变引用要么 只能有多个不可变引用。引用必须总是有效的。
2、slice 类型 slice 允许你引用集合中一段连续的元素序列而不用引用整个集合。slice 是一类引用所以它没有所有权。
以下有个slice示例
fn main() {let s String::from(hello world);let hello s[0..5];let world s[6..11];println!({}---{}, hello, world)
}
运行以下看下结果如何 根据以上结果可以知道hello变量从字符串hello world中进行截取的开始的位置为0长度为5所以打印的结果为hello而world变量是从开始索引6开始11结束11-56那么它的长度也是5所以打印的结果为world.
Slice 的主要结果包括2部分
第一部分是指针指向数据开始的位置第二部分是长度就是元素结束减去开始位置的值
以下是一个示意图能够更加清楚知道slice与字符串的关系 其他写法例如取前5个字符
fn main() {let s String::from(hello world);let hello s[0..5];let hello1 s[..5]; // hello 和 hello1 是等价的println!({}---{}, hello, hello1)
}
例如取最后5个字符
fn main() {let s String::from(hello world);let world s[6..];let world1 s[6..];println!({}---{}, world, world1)
}
取整个长度的切片
fn main() {let s String::from(hello world);let world s[..];let world1 s[..];println!({}---{}, world, world1)
} 注意字符串 slice range 的索引必须位于有效的字符边界内如果尝试从超过边界访问超出索引范围将导致panic错误。 2.1 字符串字面量其实就是一个slice
一个示例如下所示 这里 s1 的类型是 strworld 的类型也是str所以s1它是一个指向二进制程序特定位置的 slice。这也就是为什么字符串字面值是不可变的str 是一个不可变引用。
2.2 总结
所有权、借用和 slice 这些概念让 Rust 程序在编译时确保内存安全。Rust 语言提供了跟其他系统编程语言相同的方式来控制你使用的内存但拥有数据所有者在离开作用域后自动清除其数据的功能意味着你无须额外编写和调试相关的控制代码。