nazo6 knowledge

Rust

作成:2021/12/27 0:00:00

更新:Invalid Date

(2021-12-27)

気づきとかいろいろ

エラーハンドリング (2021-12-27)

Result<T, E>Option<T>がある (2021-12-27)

  • okok_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)

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

Rustのクロージャを嗜む #Rust - Qiita

はじめにこの記事では、Rustのクロージャに関する奇抜な(JavaScriptのパラダイムに似た)応用を紹介していきます。Rustらしくない書き方だと思うので、こんなこともできるんだ程度に思って…

qiita.com

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

非同期 (2021-12-27)

(2021-12-27)

ライブラリ (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に対する知識が足りてない