2
votes

I'm very new to Rust, so this most probably a stupid question to ask.

I've couple of questions.

I've these two functions:

fn modifier2(mut ptr: Box<String>) -> Box<String> {
    println!("In modifier2...");
    println!("Ptr points to {:p}, and value is {}", ptr, *ptr);

    *ptr = ptr.to_uppercase();

    println!("Exit modifier2...");
    ptr
}

fn modifier3(ptr: &mut Box<String>)  {

    println!("In modifier3...");
    println!("Ptr points to {:p}, and value is {}", ptr, *ptr);
    println!("Ptr points to {:p}, and value is {}", *ptr, **ptr);

    **ptr = "another".to_uppercase();

    //**ptr = **ptr.to_uppercase(); //error[E0614]: type `str` cannot be dereferenced

    println!("Exit modifier3...");
}

And I'm calling them like this:

let mut answer = Box::new("Hello World".to_string());    
answer = modifier2(answer);
println!("called modifier2(): {} length: {}", answer, answer.len());

let mut answer = Box::new("Hello World".to_string());    
modifier3(&mut answer);
println!("called modifier3(): {} length: {}", answer, answer.len());

This results the following, which looks fine to me:

In modifier2...
Ptr points to 0x2145fa1d990, and value is Hello World
Exit modifier2...
called modifier2(): HELLO WORLD length: 11

In modifier3...
Ptr points to 0x50426ffb60, and value is Hello World
Ptr points to 0x2145fa1dc50, and value is Hello World
Exit modifier3...
called modifier3(): ANOTHER length: 7

I've two questions:

1) In fn modifier2(mut ptr: Box) -> Box , what is the significance of making the ptr as mute? How it differs from fn modifier2(ptr: mut Box) -> Box ?

2) In the commented line in fn modifier3, i.e., **ptr = **ptr.to_uppercase();, results in an error "error[E0614]: type str cannot be dereferenced", while I can do the same uppercase() in fn modifier2?

Thanks for any help.

EDIT: If I change modifier3() like this:

fn modifier3(&mut ptr: &mut Box<String>)  {

    println!("In modifier3...");
    println!("Ptr points to {:p}, and *PTR points to {}, and value is {}", ptr, *ptr, **ptr);

    *ptr = "another".to_uppercase(); //or **ptr = *"another".to_uppercase();   

    println!("Exit modifier3...");
}

It gives the following errors:

error[E0277]: the size for values of type `str` cannot be known at compilation time
   --> src\main.rs:99:5
    |
99  |     println!("Ptr points to {:p}, and *PTR points to {}, and value is {}", ptr, *ptr, **ptr);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time

A little confused here with the usage of &mut ptr.

Thanks.

1

1 Answers

1
votes

Your first question is already answered here, so I'll keep things short. Effectively, it means that the function takes a Box<String> by value and binds it to a mutable variable. It's the same as simply doing let mut ptr = ptr on the first line of the function. It's very different from taking an argument by mutable reference. Here, we own the Box<String>, so in particular we can change it if we wish.


When you call a method on an object, the Rust compiler will perform what's known as "autoderef" to figure out exactly what method to call. See this question for some more information on that. In effect, it allows us to call methods on an object behind a reference or some other kind of pointer.

That's what's happening with **ptr.to_uppercase(). ptr is autoderef'd to a str, and then a new String gets produced by that method (see the type signature on to_uppercase).

Then, you try to deref this String twice. The first deref results in a str, but the second one fails with error[E0614]: type `str` cannot be dereferenced. You might be confusing the order of operations here. **ptr.to_uppercase() performs to_uppercase, then derefs. To change the order, use (**ptr).to_uppercase() (this actually works here, but is unidiomatic because autoderef does that kind of thing for you).

To fix the code, simply remove the derefs on that line.

fn modifier2(mut ptr: Box<String>) -> Box<String> {
    println!("In modifier2...");
    println!("Ptr points to {:p}, and value is {}", ptr, *ptr);

    *ptr = ptr.to_uppercase();

    println!("Exit modifier2...");
    ptr
}

fn modifier3(ptr: &mut Box<String>) {
    println!("In modifier3...");
    println!("Ptr points to {:p}, and value is {}", ptr, *ptr);
    println!("Ptr points to {:p}, and value is {}", *ptr, **ptr);

    **ptr = "another".to_uppercase();

    **ptr = ptr.to_uppercase(); // No error now

    println!("Exit modifier3...");
}

fn main() {
    let mut answer = Box::new("Hello World".to_string());
    answer = modifier2(answer);
    println!("called modifier2(): {} length: {}", answer, answer.len());

    let mut answer = Box::new("Hello World".to_string());
    modifier3(&mut answer);
    println!("called modifier3(): {} length: {}", answer, answer.len());
}

(playground)

The code has one Clippy warning. See this question from some tips.