65716


### 概略

現在`tmp`ディレクトリをクリーニングする、デーモンを作成しています。そこで、ある程度はRustの理解が深まってきたので、`Result`を使ってエラーハンドリングを試みましたが、ビルドの際にして以下のようなエラーが出ました。

まず第一に`Result`の理解が進んでいない事と、デーモンを組んだ経験が無いので、見通しがつかずコードを組んでいる状態です。ですので、`Result`の扱いと`デーモンの組み方`をセットで質問したいと思います。

伺いたいことは以下の2つです。

  * `Result`のエラーはどのようにして解決すべきなのでしょうか？
  * またデーモンの組み方とは？

* * *

**エラーメッセージ**

[code]

    error[E0277]: the size for values of type `str` cannot be known at compilation time
     --> src/main.rs:4:16
      |
    4 | fn clener() -> Result<str, str>{
      |                ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
      |
      = help: the trait `std::marker::Sized` is not implemented for `str`
      = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
      = note: required by `std::result::Result`
    
    error: aborting due to previous error
    
    For more information about this error, try `rustc --explain E0277`.
    error: could not compile `tmpcleaner`.
    
    To learn more, run the command again with --verbose.
    
[/code]

**現状のソースコード** (実験段階のため、かなり汚いコードになっています)

[code]

    use std::fs;
    use chrono::prelude::*;
    
    fn clener() -> Result<str, str>{
        let killer = fs::remove_dir_all("/tmp");
        let ok = "complete a mission";
        let err  = "missing a mission";
    
        match killer {        
             Ok(ok) => return Ok(ok), 
             Err(err) => return Err(err),
        }
    }
    
    fn main(){
        let localtime = Local::now().format("%H%M%S").to_string();
        let compare = "123000";
    
        if compare  == localtime {
            println!("Ture");
        }else{    
            println!("False");
        }   
    
        println!("{}", localtime);
        println!("{}", compare);
    }
    
[/code]


CC BY-SA 4.0
2020-04-17T07:19:20.427
65708
2020-04-18T06:12:35.957
2020-04-18T06:12:35.957
3060
30493
question
rust
RustのResultについての質問 error[E0277]: the size for values of type `str` cannot be known at compilation time


こんにちは。

> `Result` のエラーはどのようにして解決すべきなのでしょうか？

これはいくつかのエラーが複合しているので、1つ1つ解説します。

まずはエラーメッセージそのもの、「the size for values of type `str` cannot be known at
compilation time」について

`str` を `&'static str` にすれば解決します。 Rustでは勝手にポインタが作られたりしないので `str`
は任意長の文字列そのものを表わします。これを関数から返すということは、例えば1000文字の文字列ならば1000文字分のデータをコピーして呼出元に返すことになります。今のところRustは任意長のデータをスタックにコピーする操作は許していません。そこで
`&str` とポインタを介すると16バイト（ポインタサイズ8バイト+strのサイズ8バイト）と定サイズになるのでエラーにならなくなります。  
「`str` 型を生で使うことはない」と覚えてしまっていいでしょう。

もし、関数内で動的に生成した文字列を返したいなら `String` を使うとよいと思います。`String` は`&str` からも
`"str".to_string()` で作れるので現時点でも `String` に移行することができます。  
`&str` と `String` については [こちら](https://doc.rust-jp.rs/book/second-
edition/ch08-02-strings.html)などを参考にして下さい。

それとは別に、このコードでは返り値型を `Result<String, String>` などにしてもコンパイルは通りません。  
以下のコードでは `killer` (`remove_dir_all` の返り値) に対してマッチし、成功した場合、失敗した場合の返り値それぞれに `ok`
、 `err` を束縛しています。そしてそのまま `Ok`、 `Err` に包んで返しています。

[code]

        match killer {
            Ok(ok) => return Ok(ok),
            Err(err) => return Err(err),
        }
    
    
[/code]

Rustでは関数の最後の式は `return` 文が必要ないので以下のように書いても同じです。

[code]

        match killer {
            Ok(ok) => Ok(ok),
            Err(err) => Err(err),
        }
    
[/code]

スコープに `ok` 、 `err` の変数があるので分かりづらいですが、ここでの `ok` 、 `err` は `match` 式で導入した方の `ok`
、 `err` なので、以下のように書いても同じことです。

[code]

        match killer {
            Ok(x) => Ok(x),
            Err(y) => Err(y),
        }
    
[/code]

これは実質何もしてないので以下のように書いても同じです。

[code]

        killer
    
[/code]

`killer` は [`remove_dir_all`](https://doc.rust-
lang.org/std/fs/fn.remove_dir_all.html) の返り値なので型は `Result<(), std::io::Error>`
ですから、 `Result<&str, &str>` にはマッチせず、エラーになります。

恐らくやりたいのはok、 errのメッセージを返したいのだと思います。その場合は `remove_dir_all` の返り値は使わないので `_`
パターンを使って無視するとよいです。

まとめると、`cleaner` 関数を以下のようにするとよいでしょう。

[code]

    fn clener() -> Result<String, String> {
        let killer = fs::remove_dir_all("/tmp");
        let ok = "complete a mission";
        let err = "missing a mission";
    
        match killer {
            Ok(_) => Ok(ok.to_string()),
            Err(_) => Err(err.to_string()),
        }
    }
    
[/code]

> またデーモンの組み方とは？

一般論としては、2回フォークして不要なリソースを切り離し、カレントディレクトリや標準出入力などを調整すればよいです。[こちらの記事](https://qiita.com/0xfffffff7/items/08d9c268c728da46d20b)が詳しいようなので参考にして下さい。

しかし上記の方法はいささか手間なので別の方法もあります。1つは上記の方法をライブラリ化したものを使う方法、もう1つはsystemdのサービスにして、普通のプログラムをデーモンのように動かす方法です。

ライブラリ化したものは私は使ったことはないのですが、調べるといくつか選択肢があるようです。  
<https://crates.io/search?q=daemon>

systemdを使う方法はこちらの記事を参考にしてみて下さい。  
<https://qiita.com/DQNEO/items/0b5d0bc5d3cf407cb7ff>

以上が参考になれば幸いです。


CC BY-SA 4.0
2020-04-17T10:11:16.987
65716
2020-04-17T10:11:16.987
22816
65708
answer