Closed11

Rust

nazo6nazo6

エラーハンドリング

nazo6nazo6

Result<T, E>Option<T>がある

  • okok_or(T)で相互変換可能
  • また下のanyhowで提供されているanyhow::contextを使うことでOptionをResultにできるみたい
nazo6nazo6

汎用的なエラーはResult<T, Box<dyn std::error::Error>>

  • Boxはヒープ領域
    • ? 演算子を使ったときにBox::newがいらないのはなぜ?
  • dyn Errorの意味はあとで調べる

と思ったけどanyhowがよさそう?

  • anyhow::Result<T>で上とほぼ同じことができる
  • さらにanyhow::anyhow!マクロで手軽にエラーメッセージを作れる。これは便利
nazo6nazo6

? 演算子

  • ResultOptionを返す関数の中で使うとNoneErrのときに早期リターンできる
  • 関数をreturnするのでブロックの値を返すためには使えない(tauriのcommandsはserdeでエンコードできるものでないといけないから恐らく上のanyhowは使えない?)
    例: これはaにResultが入るわけではない
let a = {
   hoge()?
}
  • なので即時関数を使う
    参照:

https://qiita.com/nacika_ins/items/45c0d704dfa4f1f6ef5c

let a: Result<String, Box<dyn Error>> = ||{
  hoge()?
}
nazo6nazo6

非同期

nazo6nazo6
  • 非同期関数はasync fn(T) -> Uと宣言する。
    • jsのPromiseみたいにPromise<T>と包むのではなく非同期な返り値をそのまま書くみたい
  • f().awaitで呼び出す
  • Futureがなんなのかよくわかんない
nazo6nazo6

ライブラリ

  • async構文自体は言語仕様だがそれを実装するライブラリが必要?よくわかってない
  • async-stdというものもあったがやっぱりデファクトスタンダードはtokioだと思われる
nazo6nazo6

クロージャ

  • async || {}という書きかたはunstableらしい。
    • なので|| async {}と書く
    • 即時関数なら(|| async{})().await
nazo6nazo6

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)に変えたらなにかエラーがでた
    • おそらくライフタイム関連の何かだと思うが・・・今は解決できないので保留
nazo6nazo6

非同期handler関数を引数として受けとりさらにそれをtokioでspawnさせる

https://docs.rs/under/0.2.0/under/

このクレートをパク…参考にした

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にクローズされました