Asynchronous File Loading¶
Keywords: iced::Application
, iced::Command
, iced::executor
, std::io
, std::path::Path
, std::sync::Arc
, tokio::fs::read_to_string
为了实现异步文件加载,我们需要使用tokio
库
[dependencies]
tokio = { version = "1.32", features = ["fs"] }
Sandbox
不能直接执行异步函数,需要用Application
。相比于Sandbox
,Application
需要额外实现如下类型
impl Application for Editor {
// ...
type Theme; // Color theme
type Executor; // Engine for running async tasks
type Flags; // Initial state
}
此处,Theme
和Flags
类型不需要额外实现,可以分别用iced::Theme
和()
代替。默认情况下,Executor
类型需要用iced::executor::Default
代替。
在修改为Application
后,new
和update
方法的返回值标签也需要修改,new
方法返回(Self, Command<Message>)
,update
方法返回Command<Message>
。其中Command<Message>
是一个异步任务,在执行完毕后会发送一个对应类型的Message
。
impl Application for Editor {
// ...
fn new(_flags: ()) -> (Self, Command<Message>) {
(
Self {
// ...
},
Command::none(),
)
}
fn update(&mut self, message: Message) -> Command<Message> {
match message {
// ...
}
Command::none()
}
}
此后,我们需要编写用于读取文件的函数。
use std::io;
use std::path::Path;
use std::sync::Arc;
async fn load_file<T>(path: T) -> Result<Arc<String>, io::ErrorKind>
where T: AsRef<Path>
{
tokio::fs::read_to_string(path)
.await
.map(Arc::new)
.map_err(|e| e.kind())
}
在new
方法中,我们可以使用Command
来调用load_file
函数。
enum Message {
EditorEdit(text_editor::Action),
FileOpened(Result<Arc<String>, io::ErrorKind>)
}
impl Application for Editor {
// ...
fn new(_flags: ()) -> (Self, Command<Message>) {
let path = "path/to/file.txt";
let file = load_file(path);
(
Self {
// ...
},
Command::perform(
load_file(format!("{}/main.rs", env!("CARGO_MANIFEST_DIR"))),
Message::FileLoaded,
),
)
}
}
读取文件时可能会发生错误,需要对异常消息进行处理。在load_file
函数中已经通过Result
返回了对应的错误类型,只需要在update
方法中处理Message::FileOpened
即可。
struct Editor {
// ...
error: Option<io::ErrorKind>, // Use Option to store error
}
// ...
impl Application for Editor {
// ...
fn new(_flags: ()) -> (Self, Command<Message>) {
(
Self {
// ...
error: None, // Initialize error as None
},
// ...
)
}
fn update(&mut self, message: Message) -> Command<Message> {
// ...
match message {
// ...
Message::FileOpened(Error(e)) => {
self.error = Some(e); // Store error
}
}
// ...
}
}
以下为完整的main.rs
文件内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
|