Ownership of values whose variables are shadowed - rust

See some code below:
#[derive(Debug)]
struct MyString {
a: String,
}
impl MyString {
fn new(s: &str) -> Self {
MyString { a: String::from(s) }
}
}
impl Deref for MyString {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.a
}
}
impl Drop for MyString {
fn drop(&mut self) {
println!("{} dropped!", self.a);
}
}
fn main() {
let mut test1 = MyString::new("test1");
let mut test1 = MyString::new(&test1);
println!("shadow variable test1");
test1.a = String::from("test2");
}
I thought there should be a compile error because test1 is still borrowed.
However, there's no compile error, and the result is
shadow variables test1
test2 dropped
test1 dropped
So if a variable is shadowed, the value is still valid in the current scope.
But who is its owner?

From an ownership standpoint, your code is exactly equivalent to:
fn main() {
let mut test1_1 = MyString::new("test1");
let mut test1_2 = MyString::new(&test1_1);
println!("shadow variable test1");
test1_2.a = String::from("test2");
}
So test1_1 is dropped when it goes out of scope at the end of the main function.
Note also that test1_2 does not borrow test1_1, the borrow only lasts for as long as the call to MyString::new(&test1). Afterwards there is no connection between the two variables.

Related

How can we return a static reference to a variable we make in a function in rust?

struct Foo<'a>(&'a str);
impl<'a> Foo<'a> {
fn get(&self) -> &'static str {self.0}
}
fn main() {
let value: &str;
{
let foo = Foo("Test Value");
value = foo.get();
}
println!("{}", value);
}
In this test code, I need to get the value stored in foo but as str is not sized, I can't just copy it's value. I even tried cloning the str. In a real life scenario, I could just use String or make a wrapper or encapsulate it in a box and return it but is there no way I can return a static reference to a variable I create in a function? If so, how does the as_str function work in rust?
----Edit----
In this example, Neither putting 'static before str in Foo nor returning value with lifetime 'a works. What to do then?
struct Foo<'a>(&'a [i32]);
impl<'a> Foo<'a> {
fn get(&self) -> &'static [i32] {self.0}
}
fn main() {
let value: &[i32];
{
let test_value = [0, 1, 2, 3];
let foo = Foo(&test_value);
value = foo.get();
}
println!("{:?}", value);
}
You can do it like this:
struct Foo<'a>(&'a str);
impl<'a> Foo<'a> {
fn get(&self) -> &'a str {self.0}
}
fn main() {
let value: &str;
{
let foo = Foo("Test Value");
value = foo.get();
}
println!("{}", value);
}
Or like this:
struct Foo(&'static str);
impl Foo {
fn get(&self) -> &'static str {self.0}
}
fn main() {
let value: &str;
{
let foo = Foo("Test Value");
value = foo.get();
}
println!("{}", value);
}
The reason your code doesn't compile is that you're declaring you are returning a reference with a (potentially) longer lifetime. Compare the lifetime of static with that of a (self.0 has a lifetime of a).

When is it safe to extend the lifetime of references into Arenas?

I have a struct which uses Arena:
struct Foo<'f> {
a: Arena<u64>, // from the typed-arena crate
v: Vec<&'f u64>,
}
Is it safe to extend the lifetime of a reference into the arena so long as it is bound by the lifetime of the main struct?
impl<'f> Foo<'f> {
pub fn bar(&mut self, n: u64) -> Option<&'f u64> {
if n == 0 {
None
} else {
let n_ref = unsafe { std::mem::transmute(self.a.alloc(n)) };
Some(n_ref)
}
}
}
For more context, see this Reddit comment.
Is it safe to extend the lifetime of a reference into the arena so long as it is bound by the lifetime of the main struct?
The Arena will be dropped along with Foo so, in principle, this would be safe, but it would also be unnecessary because the Arena already lives long enough.
However, this is not what your code is actually doing! The lifetime 'f could be longer that the lifetime of the struct — it can be as long as the shortest-lived reference inside v. For example:
fn main() {
let n = 1u64;
let v = vec![&n];
let bar;
{
let mut foo = Foo { a: Arena::new(), v };
bar = foo.bar(2);
// foo is dropped here, along with the Arena
}
// bar is still useable here because 'f is the full scope of `n`
println!("bar = {:?}", bar); // Some(8021790808186446178) - oops!
}
Trying to pretend that the lifetime is longer than it really is has created an opportunity for Undefined Behaviour in safe code.
A possible fix is to own the Arena outside of the struct and rely on the borrow checker to make sure that it is not dropped while it is still in use:
struct Foo<'f> {
a: &'f Arena<u64>,
v: Vec<&'f u64>,
}
impl<'f> Foo<'f> {
pub bar(&mut self, n: u64) -> Option<&'f u64> {
if n == 0 {
None
} else {
Some(self.a.alloc(n))
}
}
}
fn main() {
let arena = Arena::new();
let n = 1u64;
let v = vec![&n];
let bar;
{
let mut foo = Foo { a: &arena, v };
bar = foo.bar(2);
}
println!("bar = {:?}", bar); // Some(2)
}
Just like your unsafe version, the lifetimes express that the reference to the Arena must be valid for at least as long as the items in the Vec. However, this also enforces that this fact is true! Since there is no unsafe code, you can trust the borrow-checker that this will not trigger UB.

Rust method that accepts and treats any kind of string as immutable and produces a new immutable string?

I'm new to Rust. I want to write a method (trait implementation?) that takes any of a String or a string slice, treats it as immutable, and returns a new immutable string. Let's say foo is a method that doubled whatever input you give it:
let x = "abc".foo(); // => "abcabc"
let y = x.foo(); // => "abcabcabcabc"
let z = "def".to_string().foo(); // => "defdef"
In this case, I do not care about safety or performance, I just want my code to compile for a throwaway test. If the heap grows infinitely, so be it. If this requires two trait implementations, that's fine.
Let's say foo is a method that doubled whatever input you give it.
A trait is a perfectly good way to do this, since it makes one common behavior:
trait Foo {
fn foo(&self) -> String;
}
... applied to multiple types:
impl Foo for String {
fn foo(&self) -> String {
let mut out = self.clone();
out += self;
out
}
}
impl<'a> Foo for &'a str {
fn foo(&self) -> String {
let mut out = self.to_string();
out += self;
out
}
}
Using:
let x = "abc".foo();
assert_eq!(&x, "abcabc");
let z = "shep".to_string().foo();
assert_eq!(&z, "shepshep");
Playground
The output is an owned string. Whether this value immutable or not, as typical in Rust, only comes at play at the calling site.
See also:
What's the difference between placing "mut" before a variable name and after the ":"?
If you want a borrowed string &str at the end:
trait Foo {
fn display(&self);
}
impl<T> Foo for T where T: AsRef<str> {
fn display(&self) {
println!("{}", self.as_ref());
}
}
fn main() {
"hello".display();
String::from("world").display();
}
If you want an owned String:
trait Foo {
fn display(self);
}
impl<T> Foo for T where T: Into<String> {
fn display(self) {
let s: String = self.into();
println!("{}", s);
}
}
fn main() {
"hello".display();
String::from("world").display();
}

Returning a MutexGuard of a lazy_static Mutex from a function needs a lifetime parameter

I'm writing tests using mock functions, controlling the return value among the tests with a Mutex:
#[macro_use]
extern crate lazy_static;
#[cfg(test)]
pub use mock::*;
#[cfg(not(test))]
pub use real::*;
mod real {
pub fn say_hello(_name: String) -> String {
unimplemented!()
}
}
/// simulate multiple uses, replace `real` in test.
mod mock {
use std::sync::*;
lazy_static! {
pub static ref LOCK: Mutex<bool> = Mutex::new(true);
pub static ref HELLO_VALUE: Mutex<String> = Mutex::new(String::default());
}
pub fn say_hello(_name: String) -> String {
use std::ops::Deref;
HELLO_VALUE.lock().unwrap().deref().clone()
}
pub fn set_hello_return_value(rtn: String) -> MutexGuard<bool> {
let lock = LOCK.lock().unwrap();
let mut value = HELLO_VALUE.lock().unwrap();
*value = rtn;
lock
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test1() {
// repeated block begin--------------------------
let _lock = LOCK.lock().unwrap();
let mut value = HELLO_VALUE.lock().unwrap();
*value = "Hello Tom!".to_string(); // just this line is different from test2
drop(value);
// repeat block end--------------------------
assert_eq!("Hello Tom!", say_hello("".to_string()));
}
#[test]
fn test2() {
// repeated block begin--------------------------
let _lock = LOCK.lock().unwrap();
let mut value = HELLO_VALUE.lock().unwrap();
*value = "Hello Jack!".to_string(); // just this line is different from test1
drop(value);
// repeat block end--------------------------
assert_eq!("Hello Jack!", say_hello("".to_string()));
}
#[test]
fn test_simplified_but_not_work() {
let _lock = set_hello_return_value("Hello Mark!".to_string());
assert_eq!("Hello Mark!", say_hello("".to_string()));
}
}
You can see the repeat block that I want to simplify. I made a function set_hello_return_value but the compiler complained:
error[E0106]: missing lifetime specifier
--> src/main.rs:28:51
|
28 | pub fn set_hello_return_value(rtn: String) -> MutexGuard<bool> {
| ^^^^^^^^^^^^^^^^ expected lifetime parameter
|
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
= help: consider giving it an explicit bounded or 'static lifetime
Please help me to correct it.
Read the complete error message:
consider giving it an explicit bounded or 'static lifetime
Doing so works:
pub fn set_hello_return_value(rtn: String) -> MutexGuard<'static, bool> {
let lock = LOCK.lock().unwrap();
let mut value = HELLO_VALUE.lock().unwrap();
*value = rtn;
lock
}
I'd probably not return the guard at all, however:
pub fn with_hello_return_value<S, F>(rtn: S, f: F)
where
S: Into<String>,
F: FnOnce(),
{
let _lock = LOCK.lock().unwrap();
*HELLO_VALUE.lock().unwrap() = rtn.into();
f()
}
#[test]
fn test_simplified() {
with_hello_return_value("Hello Mark!", || {
assert_eq!("Hello Mark!", say_hello("".to_string()));
});
}
Honestly, I wouldn't do any of this as conditional compilation is overkill. If you need to test components of your system separately, they shouldn't know about each other to start with; they should be dependency-injected. This has the additional benefit that each test can inject its own value, preserving the multithreaded nature of the tests.
fn thing_that_uses_say_hello<G>(greeter: &G, name: &str) -> String
where
G: Greeting,
{
greeter.say_hello(name.into())
}
trait Greeting {
fn say_hello(&self, name: &str) -> String;
}
struct RealGreeting;
impl Greeting for RealGreeting {
fn say_hello(&self, name: &str) -> String {
format!("Hello, {}", name)
}
}
#[cfg(test)]
mod test {
use super::*;
use std::cell::RefCell;
struct MockGreeting<'a> {
called_with: RefCell<Vec<String>>,
value: &'a str,
}
impl<'a> MockGreeting<'a> {
fn new(value: &'a str) -> Self {
Self {
value,
called_with: Default::default(),
}
}
}
impl<'a> Greeting for MockGreeting<'a> {
fn say_hello(&self, name: &str) -> String {
self.called_with.borrow_mut().push(name.to_owned());
self.value.to_owned()
}
}
#[test]
fn test1() {
let g = MockGreeting::new("Hello");
let r = thing_that_uses_say_hello(&g, "Tom");
assert_eq!("Hello", r);
assert_eq!(&*g.called_with.borrow(), &["Tom".to_string()]);
}
}

How to make &mut self from &self?

I want to expose a public function with immutable self which calls a private function with mutable self.
struct Foo {
value: i32,
}
impl Foo {
fn f1(&self) {
self.f2(); // <--- is it possible to make self mutable?
}
fn f2(&mut self) {
self.value = 5;
}
}
fn main() {
let foo = Foo { value: 0 };
foo.f1();
}
When compiling this code I get an error
cannot borrow immutable borrowed content *self as mutable
Is it possible to make self mutable?
EDIT:
After missing that last sentence.. you could get away with wrapping the property in a Cell:
use std::cell::Cell;
struct Foo { value: Cell<i32> }
impl Foo {
fn f1(&self) {
self.f2();
}
fn f2(&self) {
self.value.set(5);
}
}
fn main() {
let foo = Foo { value: Cell::new(0) };
foo.f1();
println!("{:?}", foo.value.get()); // prints 5
}
What you want cannot be done: you cannot convert a non-mutable reference into a mutable one.
But you can get almost that with RefCell:
struct Foo { value: RefCell<i32> }
impl Foo {
fn f1(&self) {
let mutValue = self.value.borrow_mut();
*mutValue = 5;
}
}
I didn't even need the f2 function!

Resources