(2021-12-27)
気づきとかいろいろ
エラーハンドリング (2021-12-27)
Result<T, E>
とOption<T>
がある (2021-12-27)
ok
とok_or(T)
で相互変換可能- また下の
anyhow
で提供されているanyhow::context
を使うことでOptionをResultにできるみたい
汎用的なエラーはResult<T, Box<dyn std::error::Error>>
(2021-12-27)
- Boxはヒープ領域
?
演算子を使ったときにBox::new
がいらないのはなぜ?
dyn Error
の意味はあとで調べる
と思ったけどanyhowがよさそう?
anyhow::Result<T>
で上とほぼ同じことができる- さらに
anyhow::anyhow!
マクロで手軽にエラーメッセージを作れる。これは便利
?
演算子 (2021-12-27)
Result
やOption
を返す関数の中で使うとNone
やErr
のときに早期リターンできる- 関数をreturnするのでブロックの値を返すためには使えない(tauriのcommandsはserdeでエンコードできるものでないといけないから恐らく上のanyhowは使えない?)
例: これはaにResultが入るわけではない
let a = {
hoge()?
}
- なので即時関数を使う
参照:
Rustのクロージャを嗜む #Rust - Qiita
はじめにこの記事では、Rustのクロージャに関する奇抜な(JavaScriptのパラダイムに似た)応用を紹介していきます。Rustらしくない書き方だと思うので、こんなこともできるんだ程度に思って…
qiita.com

let a: Result<String, Box<dyn Error>> = ||{
hoge()?
}
非同期 (2021-12-27)
(2021-12-27)
- 非同期関数は
async fn(T) -> U
と宣言する。- jsのPromiseみたいに
Promise<T>
と包むのではなく非同期な返り値をそのまま書くみたい
- jsのPromiseみたいに
f().await
で呼び出す- Futureがなんなのかよくわかんない
- jsではPromiseに相当するもの?
-
JavaScriptな人のためのRustのFuture入門 #JavaScript - Qiita
RustでI/Oを扱うプログラムを書く機会がありました。非同期I/Oのほうがパフォーマンスがよくなるらしく、tokio というフレームワークがよく使われているとのこと。tokio では Future…qiita.com
- jsとは違ってポーリングで非同期処理をしてる。へー
- 昔はfutureというクレートもあったが今は
std::future
で十分?
ライブラリ (2021-12-27)
- async構文自体は言語仕様だがそれを実装するライブラリが必要?よくわかってない
async-std
というものもあったがやっぱりデファクトスタンダードはtokioだと思われる
クロージャ (2021-12-27)
async || {}
という書きかたはunstableらしい。- なので
|| async {}
と書く - 即時関数なら
(|| async{})().await
- なので
reqwest (2021-12-27)
- 高レベルな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())
- streamがよくわかってないけどとりあえずこれでいける
futures_util
はなんだろう
- 最後のところを
Ok(path_str)
に変えたらなにかエラーがでた- おそらくライフタイム関連の何かだと思うが・・・今は解決できないので保留
非同期handler関数を引数として受けとりさらにそれをtokioでspawnさせる (2022-03-20)
under - Rust
Under is a batteries-included async HTTP framework built for easy development. Under is based on Tokio, an async runtime. Under is meant to take the headache out of developing HTTP servers, while still being fairly performant.
docs.rs
このクレートをパク…参考にした
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
に対する知識が足りてない