Rust
目次
Rust
- (2021-12-27)
- エラーハンドリング (2021-12-27)
- Result<T, E>とOption<T>がある (2021-12-27)
- 汎用的なエラーはResult<T, Box<dyn std::error::Error>> (2021-12-27)
- と思ったけどanyhowがよさそう?
- ? 演算子 (2021-12-27)
- 非同期 (2021-12-27)
- (2021-12-27)
- ライブラリ (2021-12-27)
- クロージャ (2021-12-27)
- reqwest (2021-12-27)
- ファイルに保存する方法
- 非同期handler関数を引数として受けとりさらにそれをtokioでspawnさせる (2022-03-20)
#(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()?
}- なので即時関数を使う 参照:
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に相当するもの?
- https://qiita.com/Kumassy/items/bc3b0bdd7ab8e414c3db
- 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())参考: https://github.com/seanmonstar/reqwest/issues/1266#issue-875945198
- streamがよくわかってないけどとりあえずこれでいける
futures_utilはなんだろう
- 最後のところを
Ok(path_str)に変えたらなにかエラーがでた- おそらくライフタイム関連の何かだと思うが・・・今は解決できないので保留
#非同期handler関数を引数として受けとりさらにそれをtokioでspawnさせる (2022-03-20)
このクレートをパク…参考にした
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)
}
}使用側:
#[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に対する知識が足りてない