Сопоставление рисунка на одной руке с разными типами - PullRequest
0 голосов
/ 16 декабря 2018

Интересно, есть ли способ упростить следующую комбинацию соответствия шаблонов, когда два или более разных типов enum имеют один и тот же элемент данных или одну и ту же функцию.

(если нет, было бы неплохо объяснить, почему)

ОБНОВЛЕНИЕ:

в соответствии с запросом более точного примера того, что я хочу (простите, что я путаю доступ к элементам данных с функцией) ( попробуйте онлайн ):

struct Point<T> {
    x: i32,
    y: T,
}

enum Record {
    V4(Point<i64>),
    V6(Point<i32>),
}

fn get_record() -> Record {
    Record::V4(Point{ x: 1, y: 1})
}

fn main() {
    let x = match get_record() {
        Record::V4(r) => r.x,
        Record::V6(r) => r.x,
    };
    println!("{}", &x);

    // this will not compile
    // let rec = get_record();
    // println!("{}", rec.x);

    // this will not compile either
    // note: if V4 Point was i32 it will compile & run
    // let rec = get_record();
    // let x = match get_record() {
    //     Record::V4(r) | Record::V6(r) => r.x,
    // };
}

Исходное сообщение:

use std::net::IpAddr;
use std::str::FromStr;

fn main() {
    let v4_or_v6 = IpAddr::from_str("1.2.3.4").unwrap();

    // match expression, both arms only differ by 1 char
    let s = match v4_or_v6 {
        IpAddr::V4(ip) => ip.to_string(),
        IpAddr::V6(ip) => ip.to_string(),
    };
    println!("{}", &s);

    // not working:
    // let s2 = match v4_or_v6 {
    //     IpAddr::V4(ip) | IpAddr::V6(ip) => ip.to_string(),
    // };
    // println!("{}", &s2);
}

Я понимаю, что основной вызов to_string() имеет другую реализацию для Ipv4, чем Ipv6, но я думаю, что компилятор может быть достаточно умен, чтобы справитьсяэто (я ошибаюсь?)

попытка компилирования с закомментированным кодом приводит к ошибке компиляции ( попробуйте онлайн ):

Compiling playground v0.0.1 (/playground)

error[E0308]: mismatched types
  --> src/main.rs:16:37
   |
16 |         IpAddr::V4(ip) | IpAddr::V6(ip) => ip.to_string(),
   |                                     ^^ expected struct `std::net::Ipv4Addr`, found struct `std::net::Ipv6Addr`
   |
   = note: expected type `std::net::Ipv4Addr`
              found type `std::net::Ipv6Addr`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
error: Could not compile `playground`.

1 Ответ

0 голосов
/ 16 декабря 2018

Рабочий код очищает от сахара:

let s = match v4_or_v6 {
    IpAddr::V4(ip) => <Ipv4Addr as ToString>::to_string(&ip),
    IpAddr::V6(ip) => <Ipv6Addr as ToString>::to_string(&ip),
};

Несмотря на то, что операторы выглядят одинаково, они являются разными функциями, и в каждой ветви статически известно, какой to_string будет использоваться.Чтобы заставить это работать в одной руке совпадения, вам нужно каким-то образом создать объект черты из сопоставления с образцом, чтобы каждый ip имел одинаковый тип (то есть &dyn ToString).В настоящее время нет способа сделать это, и я не видел ни одного подобного предложения.

Довольно часто встречаются одинаково выглядящие спичечные рукава, где для каждого вызывается один и тот же метод черты, даже вrustc проект.Пока это так.


Если у вас есть enum, где каждый вариант содержит типы, которые реализуют одинаковые черты, может быть удобно реализовать черты на enumи делегировать внутренним типам.Если у вас нет признака, но у ваших типов есть общая структура (как в полях x, y в структуре вашего обновленного сообщения), тогда вы можете предоставить аксессор на enum:

impl Record {
    fn x(&self) -> i32 {
        match self {
            Record::V4(Point { x, .. }) => *x,
            Record::V6(Point { x, .. }) => *x,
        }
    }
}

Хотя это в основном одно и то же, это означает, что вы можете написать его один раз, а не везде, к которому вам нужен доступ x:

let rec = get_record();
let x = get_record().x();

Обратите внимание, что IpAddr уже делает этоТаким образом, в исходном коде вы могли бы избежать match вместе с:

let s = v4_or_v6.to_string();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...