Клон Rust-Производного Для Определенной Структуры

#rust #rust-tokio #rust-iced

Вопрос:

Примечание: Я использую iced для графического TextInput интерфейса и tokio для работы в сети TcpStream

У меня есть следующее:

 #[derive(Debug, Clone)]
enum Message {
    Session(Result<Connection, ConnectionError>), //Async Handler
    SendMessage,
    Send(Result<Connection, ConnectionError>), //Async Handler
    InputChanged(String),
    Button(usize, ButtonMessage),
    None,
}

#[derive(Debug)]
enum ConnectionError {
    ConnectError(usize),
    SendError(usize),
}

#[derive(Debug)]
struct Connection {
    stream: TcpStream,
    loc: usize,
}
 

Проблема в том, что моя Connection структура содержит TcpStream то, что не может быть клонировано (в любом случае с точки зрения логистики клонировать ее было бы бессмысленно).

Поэтому я получаю ошибку…

 >the trait bound `Connection: Clone` is not satisfied
  --> srcmain.rs:27:10
   |
27 |     Session(Result<Connection, ConnectionError>), //Async Handler
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `Clone`
   |
   = note: required because of the requirements on the impl of `Clone` for `std::result::Result<Connection, ConnectionError>`
   = note: required by `clone`
   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

>error[E0277]: the trait bound `ConnectionError: Clone` is not satisfied
  --> srcmain.rs:27:10
   |
27 |     Session(Result<Connection, ConnectionError>), //Async Handler
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `Clone`
   |
   = note: required because of the requirements on the impl of `Clone` for `std::result::Result<Connection, ConnectionError>`
   = note: required by `clone`
   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

>error[E0277]: the trait bound `Connection: Clone` is not satisfied
  --> srcmain.rs:29:7
   |
29 |     Send(Result<Connection, ConnectionError>), //Async Handler
   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `Clone`
   |
   = note: required because of the requirements on the impl of `Clone` for `std::result::Result<Connection, ConnectionError>`
   = note: required by `clone`
   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

>error[E0277]: the trait bound `ConnectionError: Clone` is not satisfied
  --> srcmain.rs:29:7
   |
29 |     Send(Result<Connection, ConnectionError>), //Async Handler
   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `Clone`
   |
   = note: required because of the requirements on the impl of `Clone` for `std::result::Result<Connection, ConnectionError>`
   = note: required by `clone`
   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
 

Поэтому я удалил Клона

 #[derive(Debug)]
enum Message {
    Session(Result<Connection, ConnectionError>), //Async Handler
    SendMessage,
    Send(Result<Connection, ConnectionError>), //Async Handler
    InputChanged(String),
    Button(usize, ButtonMessage),
    None,
}
 

and get the following errors:

 >the trait bound `Message: Clone` is not satisfied
   --> srcmain.rs:516:15
    |
516 |         let input = TextInput::new(
    |                     ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `Message`
    |
   ::: C:Usersbratl.cargoregistrysrcgithub.com-1ecc6299db9ec823iced_native-0.3.0srcwidgettext_input.rs:84:22
    |
84  |         F: 'static   Fn(String) -> Message,
    |                      --------------------- required by this bound in `iced_native::widget::text_input::TextInput::<'a, Message, Renderer>::new`

>error[E0599]: no method named `padding` found for struct `iced_native::widget::text_input::TextInput<'_, Message, iced_graphics::renderer::Renderer<iced_wgpu::backend::Backend>>` in the current scope
   --> srcmain.rs:522:4
    |
26  | enum Message {
    | ------------ doesn't satisfy `Message: Clone`
...
522 |         .padding(15)
    |          ^^^^^^^ private field, not a method
    |
    = note: the method `padding` exists but the following trait bounds were not satisfied:
            `Message: Clone`
 

So I went to where the TextInput was located and removed the Clone as well.

 #[derive(Debug)]
struct ClientAdminChatPaneContent {
    scroll: scrollable::State,
    input: text_input::State,
    input_value: String,
}


#[derive(Debug)]
enum ChatPaneMessage {
    InputChanged(String),
}

impl ClientAdminChatPaneContent {
    fn new() -> Self {
        ClientAdminChatPaneContent { 
            scroll: scrollable::State::new(),
            input: text_input::State::new(),
            input_value: String::from(""),
        }
    }

    fn update(amp;mut self, message: ChatPaneMessage) {
        match message {
            ChatPaneMessage::InputChanged(value) => {
                //println!("Input Changed: {}", value);
                self.input_value = value;
            }
        }
    }

    fn view(amp;mut self) -> Element<Message> {

        //Text Input
        let input = TextInput::new(
            amp;mut self.input,
            "Message to Client",
            amp;self.input_value,
            Message::InputChanged,
        )
        .padding(15)    
        .size(30)
        .on_submit(Message::SendMessage);
        
        let text_input_container:Container<Message> = Container::new(input)
            .width(Length::Fill)
            .height(Length::Units(80))
            .padding(10);

        let scroll = Scrollable::new(amp;mut self.scroll)
            .width(Length::Fill)
            .spacing(10)
            .align_items(Align::Start);

        let scroll_container:Container<Message> = Container::new(scroll)
            .width(Length::Fill)
            .height(Length::Fill)
            .padding(10);

        let mut content = Column::new()
            .spacing(5);

        content = content.push(scroll_container);
        content = content.push(text_input_container);

        Container::new(content)
            .width(Length::Fill)
            .height(Length::Fill)
            .padding(5)
            .center_y()
            .into()
    }

    fn clear_text(amp;mut self) {
        self.input_value = String::from("");
    }
}
 

И я получаю новую ошибку:

 >the trait bound `Message: Clone` is not satisfied
   --> srcmain.rs:516:15
    |
516 |         let input = TextInput::new(
    |                     ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `Message`
    |
   ::: C:Usersbratl.cargoregistrysrcgithub.com-1ecc6299db9ec823iced_native-0.3.0srcwidgettext_input.rs:84:22
    |
84  |         F: 'static   Fn(String) -> Message,
    |                      --------------------- required by this bound in `iced_native::widget::text_input::TextInput::<'a, Message, Renderer>::new`
 

Что касается того, почему, я не уверен, почему let input = TextInput::new( необходимо реализовать Clone . Но, предполагая, что мне нужна эта структура для реализации клонирования, БЕЗ Message реализации клонирования из-за TCP…

Как мне получить клон для определенного элемента, например a TextInput , не выводя его для каждого отдельного элемента, или это совершенно другая проблема?

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

1. Эти три факта не все могут быть правдой: (1) Message содержит Connection . (2) Message выводит Clone . (3) Connection не реализуется Clone . На данный момент никто другой не может вам помочь: вы должны решить, какой из этих трех фактов должен дать, чтобы остальные могли остаться. Лично я подозреваю, что вам следует исключить (1) — в каком смысле имеет смысл, чтобы сообщение содержало соединение ? — но в конечном счете это определяется тем, как вы его используете. Нет никакого общего взлома или обходного пути; вещь либо есть Clone , либо ее нет. Я не знаю, что еще ты ожидаешь услышать.

2. Это может помочь внести некоторую косвенность в данные, хранящиеся в ваших структурах, чтобы их можно было клонировать. Вы можете обернуть TcpStream в Rc (и RefCell, если вам нужно его изменить). Rc может быть клонирован без клонирования ссылки, которой он владеет, так как он просто увеличивает внутреннее количество ссылок

3. @trentcl Приношу свои извинения. Я на 100% понимаю, о чем вы говорите. И я полностью согласен с тем, что a Message не должно содержать a Connection . Я пытался вернуть a Connection из асинхронной функции, скажем, после send функции для TcpStream . Теперь я понимаю, что это было ошибкой. Спасибо!

4. Не нужно извиняться! Рад, что смог помочь, хотя бы в малой степени.

5. Не то чтобы я совсем понимал, как это исправить, или мысль о том, что я могу вернуть Result<(), ConnectionError> что-то вроде удара по мне. Понемногу. 🙂