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

У меня есть этот код (bb42e59) :

pub extern crate r2d2;
pub extern crate tiberius;
pub extern crate futures;

use self::tiberius::BoxableIo;
use self::futures::prelude::*;

use core::fmt::Debug;
#[allow(unused_imports)]
use std::error::Error;

type TiberiusConnection = self::tiberius::SqlConnection<Box<BoxableIo>>;

#[derive(Debug)]
pub enum Errors { TiberiusError(tiberius::Error) }

#[derive(Debug)]
pub struct MSSQLConnectionManagerError(Errors);

impl ::std::error::Error for MSSQLConnectionManagerError {
    fn description(&self) -> &str {
        match self.0 {
            Errors::TiberiusError(ref e) => {
                match e {
                    tiberius::Error::Io(e) => e.description(),
                    tiberius::Error::Protocol(msg) => &msg,
                    tiberius::Error::Encoding(msg) => &msg,
                    tiberius::Error::Conversion(msg) => &msg,
                    tiberius::Error::Utf8(e) => e.description(),
                    tiberius::Error::Utf16(e) => e.description(),
                    tiberius::Error::ParseInt(e) => e.description(),
                    // TODO: parse the server token if possible and report the actual error that occurred, like invalid login, etc.
                    tiberius::Error::Server(_) => "TDS token error occurred! When connecting, most often an invalid login.",
                    tiberius::Error::Canceled => "Canceled!",
                }
            }
        }
    }
}

impl ::std::fmt::Display for MSSQLConnectionManagerError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match self.0 { Errors::TiberiusError(ref e) => e.fmt(f), }
    }
}

pub struct MSSQLConnection(TiberiusConnection);

pub struct MSSQLConnectionManager { connection_string: String }

impl MSSQLConnectionManager {
    pub fn new(connection_string: String) -> MSSQLConnectionManager {
        MSSQLConnectionManager { connection_string }
    }

    pub fn from_env() -> Result<MSSQLConnectionManager, ::std::env::VarError> {
        let connection_string = ::std::env::var("MSSQL_CONNECTION_STRING")?;
        Ok(MSSQLConnectionManager { connection_string })
    }
}

impl r2d2::ManageConnection for MSSQLConnectionManager {
    type Connection = MSSQLConnection;
    type Error = MSSQLConnectionManagerError;

    fn connect(&self) -> Result<Self::Connection, Self::Error> {
        let connection_result = TiberiusConnection::connect(&self.connection_string)
            .and_then(|c| Ok(c)).wait();
        match connection_result {
            Ok(c) => Ok(MSSQLConnection(c)),
            Err(e) => Err(MSSQLConnectionManagerError(Errors::TiberiusError(e))),
        }
    }

    fn is_valid(&self, _conn: &mut Self::Connection) -> Result<(), Self::Error> {
        // TODO: Fix this quick and dirty implementation by checking the result of a simple query.
        Ok(())
    }

    fn has_broken(&self, _conn: &mut Self::Connection) -> bool {
        // TODO: Fix this quick and dirty implementation by checking underlying TCP socket state.
        false
    }
}

Компилятор жалуется на Ok(c) => Ok(Self::Connection(c)),:

error[E0599]: no associated item named `Connection` found for type `persistence::mssql::MSSQLConnectionManager` in the current scope
  --> src/persistence/mssql.rs:77:25
   |
56 | pub struct MSSQLConnectionManager { connection_string: String }
   | --------------------------------- associated item `Connection` not found for this
...
77 |             Ok(c) => Ok(Self::Connection(c)),
   |                         ^^^^^^^^^^^^^^^^ associated item not found in `persistence::mssql::MSSQLConnectionManager`

Когда я пишу это явно, какthis:

match connection_result {
    Ok(c) => Ok(MSSQLConnection(c)),
    Err(e) => Err(MSSQLConnectionManagerError(Errors::TiberiusError(e))),
}

Теперь он успешно компилируется.Я получаю ту же ошибку компилятора, хотя, если я пытаюсь сделать это с L10, возвращая Err(Self::Error(e)).

Почему это не работает так, как я ожидаю?

1 Ответ

0 голосов
/ 04 октября 2018

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

trait Manager {
    type Connection;

    fn connect(&self) -> Self::Connection;
}

pub struct ConnectionId(usize);

pub struct FooManager;

impl Manager for FooManager {
    type Connection = ConnectionId;

    fn connect(&self) -> Self::Connection {
        Self::Connection(5)
    }
}

Ошибка возникает при попытке использовать связанный тип Connection в качестве псевдонима для конкретного типа ConnectionId, как это определено реализацией Manager,Однако связанные типы не ведут себя полностью как псевдоним типа.Несмотря на то, что мы можем создать ConnectionId (так как это структура кортежа, и мы видим ее элемент в этом модуле), мы не можем сделать это через связанный тип Self::Connection.Что мы могли бы сделать, так это получить доступ к другим символам, определенным его ограничениями.Например, если бы у нас было это:

trait Manager {
    type Connection: Default;
    // ...
}

Мы могли бы вызвать default из Self::Connection.

Таким образом, изменив выражение Ok(Self::Connection(c)) в исходном примерена Ok(MSSQLConnection(c)), это правильный способ исправить это.В случае, если вам нужно абстрагировать тип даже на этом этапе, вы можете ограничить связанный тип новой чертой, обеспечивающей необходимые методы построения.

...