Почему метод раскрашивания признака может быть вызван для строки, в то время как строка не включает раскрашивание

#rust

Вопрос:

Из Colorize документа о чертах, String не включает его (в то время как amp;str включает его).

 fn blue(self) -> ColoredString
where
    Self: Sized, 
 

Но почему String тип может вызывать свой метод?

 use colored::Colorize;

fn main() {
    let blue = "blue".to_owned().blue();
    println!("{}", blue);
}

 

правки

  • [неразрешено] Как я могу его удалить? (в частности, чтобы выяснить, происходит ли автоматическое отключение)
  • Что происходит под капотом?

Введите принуждение при вызовах методов. String может быть принужден к amp;str amp;*String

Ответ №1:

Признак Colorize реализован для amp;'a str и String реализует Deref<Target=str> .

Правила вызова метода Rust означают, что значение может быть автоматически заимствовано или разыменовано.

Это означает , что для нашего вызова метода String Rust будет искать какой-либо метод, который имеет один из следующих типов в качестве типа приемника

  • String
  • amp;String
  • amp;mut String
  • str (автор дереф)
  • amp;str (это позволяет вызову метода работать)
  • amp;mut str

Поскольку String он только заимствуется, вы можете использовать его после звонка .blue()

 use colored::Colorize;

fn main() {
    let x = "hello".to_string();
    let y = x.blue();

    println!("{}", x);
    println!("{}", y);
}
 

ссылка на ссылку rust о том, как разрешаются вызовы методов

Комментарии:

1. Я думаю x , что перемещается, как его называют, с blue тех пор, как он получает self . Правильно, это тип принуждения! Трудно запомнить эти кусочки сахара.

2. x не перемещается, так self как есть amp;str , а общие ссылки есть Copy .

Ответ №2:

Причина String , по-видимому, в поддержке черт, реализованных для amp;str , связана с его реализацией Deref с целевым типом str . Сама строка на самом деле не поддерживает эти функции, но . оператор действует как своего рода разыменование, предоставляющее доступ к методам, поддерживаемым amp;str .

Ниже приведен минимальный объем кода, необходимый для изоляции и демонстрации того же поведения.

 #[derive(Debug)]
enum ColoredString { Blue }

trait Colorize {
    fn blue(self) -> ColoredString
    where
        Self: Sized,
    {
        ColoredString::Blue
    }
}

impl Colorize for amp;str { }  // <-- `Colorize` only impl'd for `amp;str`.

fn main() {
    let s = "a string".to_string();
    println!("{:?}", s.blue());     // <-- Invoking `.blue()` on `String`
}
 

выход

 Blue
 

Реализуя Colorize for amp;str , .blue() можно вызвать on String . Если мы реализуем Deref для произвольной структуры то же самое String , мы должны быть в состоянии воспроизвести то же поведение.

         :   // Continued from above example...
        :
impl Colorize for amp;str { }  // <-- `Colorize` only impl'd for `amp;str`.

use std::ops::Deref;

struct Foo { }              // <-- Arbitrary struct.

impl Deref for Foo {        // <-- Implements `Deref<Target = str>`.
    type Target = str;
    fn deref(amp;self) -> amp;Self::Target {
        "I am Foo!"
    }
}

fn main() {
    let f = Foo { };
    
    println!("{:?}", amp;*f);          // <-- Simple deref.
    println!("{:?}", f.blue());     // <-- Invoking `.blue()` on `Foo`.
}
 

выход

 "I am Foo!"
Blue
 

ссылка на игровую площадку

И это работает; Foo вышеуказанные поддержки Colorize точно так String же работают, реализуя Deref с Target = str помощью .

Foo Colorize на самом деле эта черта вообще не поддерживается — она просто возвращает amp;str значение при разыменовании, которое компилятор учитывает при разрешении вызова метода.

Комментарии:

1. но , читая источник colored , это только подразумевает amp;str .

2. в этом случае его трудно расширить из-за правила сироты; У меня нет ни цветного, ни строкового источника. Оказывается, это связано с принуждением типа при вызовах методов.

3. @Izana ах, я понимаю.. Сейчас я смотрю на источники и вижу , что в них нет явного impl Colored for String , но каким-то образом компилятор справляется с вызовом признака в строке.

4. Хорошо @Izana… У меня есть отдельный пример того, как происходит волшебство. И в моем примере я получил произвольную структуру для поддержки Colorize , используя тот же механизм, который обеспечивает String поддержку той же черты.