Специализация: она вроде есть или все-таки ее нет?

начну с конца - в стандартной библиотеке есть типаж From, у которого есть такие реализации:

impl From<Box<str>> for String
impl<'a> From<&'a str> for String
impl<'a> From<Cow<'a, str>> for String

и там-же есть общая реализация:

impl<T> From<T> for T

и в системной библиотеке это работает, а у меня почему-то нет:

pub trait GetterExt<T> {
    type Err;
    fn get_value(&self, path: impl AsRef<str>) -> Result<Option<T>, Self::Err>;
}

impl<T: FromStr> GetterExt<T> for Value {
    type Err = T::Err;
    fn get_value(&self, path: impl AsRef<str>) -> Result<Option<T>, T::Err> {
        let mut cursor = self;
        for name in path.as_ref().split(unsafe { SEPARATOR }) {
            println!("{}", name);
            match cursor.get(name) {
                Some(next) => {
                    cursor = next;
                }
                None => {
                    return Ok(None);
                }
            }
        }

        format!("{}", cursor).as_str().parse().map(|v| Some(v))
    }
}

impl GetterExt<f64> for Value {
    type Err = ();
    fn get_value(&self, path: impl AsRef<str>) -> Result<Option<f64>, Self::Err> {
        let mut cursor = self;
        for name in path.as_ref().split(unsafe { SEPARATOR }) {
            println!("{}", name);
            match cursor.get(name) {
                Some(next) => {
                    cursor = next;
                }
                None => {
                    return Ok(None);
                }
            }
        }

        Ok(cursor.as_float())
    }
}

ошибка:

error[E0119]: conflicting implementations of trait `GetterExt<f64>` for type `toml::value::Value`:
  --> config/src/lib.rs:61:1
   |
41 | impl<T: FromStr> GetterExt<T> for Value {
   | --------------------------------------- first implementation here
...
61 | impl GetterExt<f64> for Value {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `toml::value::Value`

я чего-то не врубаюсь - что все-таки можно сейчас, а что нельзя?

Насколько я знаю, специализацию еще не стабилизировали, но стандартной библиотеке разрешено использовать всякие ночные штуки, в том числе и #![feature(specialization)]. Подозреваю, в этом дело.

читал + Implement RFC 1210: impl specialization,
все равно не понятно в каком сейчас это состоянии :frowning:

FromStr реализован для f64, о чем тебе и говорит компилятор, что для него T: FromStr и f64 выглядят одинаково, ибо f64: FromStr

Разве не в этом и есть суть специализации? Выделить среди конкурирующих реализаций более специфичную.

FromStr реализован для f64

согласен. Но вопрос про специализацию.

Попробуй паттерн newtype.

Думай как компилятор. Вот ты создаешь функцию:

fn do_smt<T: FromStr>(t: T) {
}

И внутри нее вызываешь общую GetterExt<T>. Что в данном случае должен сделать компилятор, когда и f64 и T: FromStr - это один и тот же T?

Потому что вот это специализация:

use std::str::FromStr;

trait MyTrait<T> {
    fn nothing();
}

struct MyStruct {
    
}

struct B {
    
}

impl MyTrait<B> for MyStruct {
    fn nothing() {}
}

impl<T: FromStr> MyTrait<T> for MyStruct {
    fn nothing() {}
}

fn main() {

}

А то, что пытаешься сделать ты - конфликтная специализация)

попробовал, не помогает :frowning:
Я помню что-то про специализацию пробегало, надо рилиз-ноутах поискать,
по-моему что-то связанное с to_owned

вот нашел - Announcing Rust 1.9

Специализация как-то так должна выглядеть:

#![feature(specialization)]

trait A {
    fn f(&self);
}

impl<T> A for T {
    default fn f(&self) {
        println!("default");
    }
}

struct S1;

impl A for S1 {
    fn f(&self) {
        println!("special case");
    }
}

struct S2;

fn main() {
    S1.f(); // special case
    S2.f(); // default
}

Вроде, решили что default требуется указывать для “родительской” реализации всегда.

Playground


@chessnokov в чем именно у тебя вопрос-то? Ночная версия специализации работает в целом как в рфц и описано было. До стабилизации этой фиче еще далековато, в задаче выше есть список пустых чекбоксов со ссылками.

1 лайк

Ну да, но это требует #![feature(specialization)] и специального указания default fn, чтобы у компилятора было дерево выбора. @chessnokov, думай как компилятор, и всё будет ОК! =)

Теперь все понятно, в stable специализации пока нет.
Спасибо.