Почему ошибка: ошибка [E0614]: тип `str` не может быть разыменован - PullRequest
2 голосов
/ 29 марта 2020

Я очень плохо знаком с Rust, так что, скорее всего, это глупый вопрос.

У меня есть пара вопросов.

У меня есть две функции:

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...");
}

И я называю их так:

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());

Это приводит к следующему, что мне подходит:

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

У меня два вопроса:

1) В модификаторе fn2 (mut ptr: Box) -> Box, каково значение создания ptr как немого? Чем он отличается от модификатора fn2 (ptr: mut Box) -> Box?

2) В закомментированной строке в модификаторе fn3, т. Е. ** ptr = ** ptr.to_uppercase () ;, приводит к ошибка "ошибка [E0614]: тип str не может быть разыменован", в то время как я могу сделать ту же заглавную букву () в модификаторе fn2?

Спасибо за любую помощь.

РЕДАКТИРОВАТЬ: Если я измените модификатор 3 () следующим образом:

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...");
}

Это дает следующие ошибки:

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

Здесь немного запутано использование & mut ptr.

Спасибо.

1 Ответ

1 голос
/ 29 марта 2020

На ваш первый вопрос уже дан ответ здесь , поэтому я буду кратким. Фактически это означает, что функция принимает значение Box<String> и связывает его с изменяемой переменной. Это то же самое, что просто сделать let mut ptr = ptr в первой строке функции. Это очень отличается от принятия аргумента с помощью изменяемой ссылки . Здесь у нас есть Box<String>, поэтому, в частности, мы можем изменить его, если мы будем sh.


Когда вы вызываете метод для объекта, компилятор Rust выполнит то, что известно как " autoderef ", чтобы выяснить, какой именно метод вызывать. См. этот вопрос для получения дополнительной информации об этом. По сути, это позволяет нам вызывать методы объекта за ссылкой или каким-либо другим указателем.

Вот что происходит с **ptr.to_uppercase(). ptr автоматически определяется по str, и затем этим методом создается новый String (см. сигнатура типа в to_uppercase).

Затем, Вы пытаетесь разорвать это String дважды. Первый разырез дает str, а второй дает error[E0614]: type `str` cannot be dereferenced. Вы можете запутать порядок операций здесь. **ptr.to_uppercase() выполняет to_uppercase, затем разыменовывает. Чтобы изменить порядок, используйте (**ptr).to_uppercase() (на самом деле это работает, но unidiomati c, потому что autoderef делает такие вещи за вас).

Чтобы исправить код, просто удалите разыменования в этой строке .

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());
}

(детская площадка)

Код имеет одно предупреждение Clippy. См. этот вопрос из нескольких советов.

...