LINUX.ORG.RU

Почему String::push_str() принимает и &str и &string

 ,


0

5

Здравствуйте

fn main() {
    let mut s1 = "Hello".to_string();
    let s2 =  String::from(", world");
    s1.push_str(&s2);
    s1.push_str("!");
    println!("{}", s1);
}

Четвертая строчка по-идее работать не должна, поскольку push_str по определению принимает &str..

fn push_str(&mut self, string: &str)

Но всё работает. Почему?

★★★★★

Последнее исправление: makoven (всего исправлений: 1)

Ответ на: комментарий от intelfx

Я не знаю. Не дочитал еще до таких глубин. В 8 главе внезапно, без объяснения причин начали работать с &string как со &str

makoven ★★★★★
() автор топика

Паста из первой редакции Книги:

Strings will coerce into &str with an &:

fn takes_slice(slice: &str) {
    println!("Got: {}", slice);
}

fn main() {
    let s = "Hello".to_string();
    takes_slice(&s);
}

This coercion does not happen for functions that accept one of &str’s traits instead of &str. For example, TcpStream::connect has a parameter of type ToSocketAddrs. A &str is okay but a String must be explicitly converted using &*.

use std::net::TcpStream;

TcpStream::connect("192.168.0.1:3000"); // Parameter is of type &str.

let addr_string = "192.168.0.1:3000".to_string();
TcpStream::connect(&*addr_string); // Convert `addr_string` to &str.

Viewing a String as a &str is cheap, but converting the &str to a String involves allocating memory. No reason to do that unless you have to!

Virtuos86 ★★★★★
()
Последнее исправление: Virtuos86 (всего исправлений: 1)

Это ещё самый простой вариант, из-за deref. Из-за отсутствия перегрузки методов используют шаблонные методы, типа:

use std::fmt::Debug;

#[derive(Debug)]
enum Value {
    Int(i32),
    Float(f64),
}

impl From<i32> for Value {
    fn from(v: i32) -> Self {
        Value::Int(v)
    }
}

impl From<f64> for Value {
    fn from(v: f64) -> Self {
        Value::Float(v)
    }
}

fn func<V: Into<Value> + Debug>(v: V) {
    println!("{:?}", v.into());
}

fn main() {
    func(1);
    func(1.5);
}

http://hermanradtke.com/2015/05/06/creating-a-rust-function-that-accepts-stri...

RazrFalcon ★★★★★
()
Ответ на: комментарий от intelfx

Всем спасибо

А вот это тоже deref coercion?

fn main() {
    let mut s1: String = "Hello".to_string();
    s1 = s1 + ", world";
    s1 = s1 + &"!";
    println!("{}", s1);
}

+ - это функция add, которая принимает &str. Но она прекрасно съедает и &«str» и просто «str». И даже &&«str», что уже вообще перебор

makoven ★★★★★
() автор топика
Последнее исправление: makoven (всего исправлений: 2)
Ответ на: комментарий от makoven

Да. Она без проблем заглотит и &&&str, и &&&&str. А ещё Deref Coercions работают не только со строками, но и с вектором (&Vec<T> в &[T]), OsString, CString, Arc, Rc, Box и т.д.

Deleted
()
Ответ на: комментарий от Deleted

Она без проблем заглотит и &&&str, и &&&&str

Боюсь спросить, а не являются ли ли такие синтаксические вольности источником ошибок?

makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

Ссылка на ссылку - это и есть ссылка. Компилятор уберёт ненужные &.

Можно через clippy прогнать, он скажет где лишние.

RazrFalcon ★★★★★
()
Ответ на: комментарий от makoven

Бывает. Но смысла в более чем одном слое ссылок особо нет.

Deleted
()
Ответ на: комментарий от Virtuos86

Да, но если нужно переменное число аргументов - придётся с tuple возится. Но в целом тот же код будет.

Хз, почему авторы не сделали перегрузку. Внятных ответов не видел.

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

Возможно когда нибудь в расте будут дженерики с переменным числом аргементов, а пока что ждём Пи-Типов (:

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.