Closed11
Rust
気づきとかいろいろ
エラーハンドリング
Result<T, E>
とOption<T>
がある
-
ok
とok_or(T)
で相互変換可能 - また下の
anyhow
で提供されているanyhow::context
を使うことでOptionをResultにできるみたい
Result<T, Box<dyn std::error::Error>>
汎用的なエラーは- Boxはヒープ領域
-
?
演算子を使ったときにBox::new
がいらないのはなぜ?
-
-
dyn Error
の意味はあとで調べる
anyhowがよさそう?
と思ったけど-
anyhow::Result<T>
で上とほぼ同じことができる - さらに
anyhow::anyhow!
マクロで手軽にエラーメッセージを作れる。これは便利
?
演算子
-
Result
やOption
を返す関数の中で使うとNone
やErr
のときに早期リターンできる - 関数をreturnするのでブロックの値を返すためには使えない(tauriのcommandsはserdeでエンコードできるものでないといけないから恐らく上のanyhowは使えない?)
例: これはaにResultが入るわけではない
let a = {
hoge()?
}
- なので即時関数を使う
参照:
let a: Result<String, Box<dyn Error>> = ||{
hoge()?
}
非同期
- 非同期関数は
async fn(T) -> U
と宣言する。- jsのPromiseみたいにPromise<T>と包むのではなく非同期な返り値をそのまま書くみたい
-
f().await
で呼び出す - Futureがなんなのかよくわかんない
- jsではPromiseに相当するもの?
- https://qiita.com/Kumassy/items/bc3b0bdd7ab8e414c3db
- jsとは違ってポーリングで非同期処理をしてる。へー
- 昔はfutureというクレートもあったが今は
std::future
で十分?
ライブラリ
- async構文自体は言語仕様だがそれを実装するライブラリが必要?よくわかってない
-
async-std
というものもあったがやっぱりデファクトスタンダードはtokioだと思われる
クロージャ
-
async || {}
という書きかたはunstableらしい。- なので
|| async {}
と書く - 即時関数なら
(|| async{})().await
- なので
reqwest
- 高レベルなHTTPクライアント
ファイルに保存する方法
use futures_util::StreamExt;
use tokio::io::AsyncWriteExt;
let file_dir = path.parent().ok_or(anyhow!("Invalid path"))?;
if !file_dir.is_dir() {
create_dir_all(file_dir).await?;
}
let mut file = tokio::fs::File::create(&path).await?;
while let Some(item) = stream.next().await {
file.write_all_buf(&mut item?).await?;
}
let path_str = path.to_str().ok_or(anyhow!("?"))?;
Ok(path_str.to_string())
参考: https://github.com/seanmonstar/reqwest/issues/1266#issue-875945198
- streamがよくわかってないけどとりあえずこれでいける
-
futures_util
はなんだろう
-
- 最後のところを
Ok(path_str)
に変えたらなにかエラーがでた- おそらくライフタイム関連の何かだと思うが・・・今は解決できないので保留
非同期handler関数を引数として受けとりさらにそれをtokioでspawnさせる
このクレートをパク…参考にした
handler.rs
use async_trait::async_trait;
use std::future::Future;
use std::pin::Pin;
use crate::error::Error;
#[async_trait]
pub trait Handler: Send + Sync + 'static {
#[must_use]
async fn apply(self: Pin<&Self>, request: [request]) -> Result<[response], Error>;
}
#[async_trait]
impl<F, Fut> Handler for F
where
F: Fn(String) -> Fut + Sync + Send + 'static,
Fut: Future<Output = Candidates> + Send + 'static,
{
async fn apply(self: Pin<&Self>, request: [request]) -> Result<[response], Error> {
Ok(self(request).await)
}
}
使用側:
main.rs
#[tokio::main]
async fn main() {
let server = Server::new(handler);
let result = server.start().await;
}
async fn handler(request: [request]) -> [response] {
[response]
}
pub struct Server {
handler: Arc<Pin<Box<dyn Handler>>>,
}
impl Server {
pub fn new<H: Handler>(handler: H) -> Self {
Server {
handler
}
}
pub async fn start(self) -> Result<(), Error> {
let listener = TcpListener::bind((self.address, self.port)).await?;
loop {
let (stream, socket) = listener.accept().await?;
let getter = Arc::clone(&self.candidates_getter);
tokio::spawn(async move {
info!("Socket connected: {}:{}", socket.ip(), socket.port());
Self::process(stream, getter).await
});
}
}
async fn process(
stream: TcpStream,
handler: Arc<Pin<Box<dyn Handler>>>,
) -> Result<(), Error> {
let handler_resut = (*handler).as_ref().apply([handler_prameters]).await;
}
}
正直なんでこれで動くかはよくわかってない
Pin
に対する知識が足りてない
このスクラップは2022/05/29にクローズされました