TAKOYAKING’s blog 一覧

TAKOYAKING’s blog

たこ焼き系

Rust: use std::io::prelude::*;

Rustでファイル操作をするときにpreludeとuseするのが気になったので、備忘録として残します。

std::io::prelude

std::io::prelude - Rust
よく使用されるioのtraitをimportしてくれる便利なもの

コード

以下のコードはファイルを読み込んでprintする

use std::fs;
use std::path::Path;
use std::io;
use std::io::prelude::*;
use std::io::BufReader;

fn main() {
    cat().unwrap_or_else(|why| panic!(why));
}

fn cat() -> io::Result<()> {
    let path_name = "takoyaki.txt";
    let path = &Path::new(path_name);
    let f = fs::File::open(path)?;
    
    for result in BufReader::new(f).lines() {
        let l = result?;
        println!("{}", l);
    }
    Ok(())
}

これなら問題なく動きます。

もしuse std::io::prelude::*;を記述しなければ以下のようなエラーになる

error[E0599]: no method named `lines` found for struct `std::io::BufReader<std::fs::File>` in the current scope
  --> src/main.rs:17:42
   |
17 |     for (i, result) in BufReader::new(f).lines().enumerate() {
   |                                          ^^^^^ method not found in `std::io::BufReader<std::fs::File>`
   |
   = help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
   |
1  | use std::io::BufRead;
   |

回避方法は以下の2つのうちのどちらかを記述すればOkです。

  • use std::io::prelude::*;
  • use std::io::BufRead;

読み方

プレリュード?

Rust: VSCodeでlibに追加したものをuseすると補完が効かない時

lib.rsで追加したものをmain.rs内でuseして使おうとすると、VSCodeの補完が出ない時がありました。

現象

// プロジェクト名: osaka
src
> lib.rs
> main.rs
use osaka::Takoyaki;
fn main() {
    let takoyaki = Takoyaki {x: 777};
}

このような感じで記述すると、VSCodeでは補完が出ません。構造体のTakoyakiの上にカーソルを合わしても、何も表示してくれません。

解決方法

extern crateをつける

extern crate osaka; // ここです
use osaka::Takoyaki;
fn main() {
    let takoyaki = Takoyaki {x: 777};
}

extern crateをつけてあげると補完が動いてくれます。

感想

extern crateなくてもコンパイルは通るのですが、補完を優先したいので、書いていきたいと思います。

Rust: VSCodeでlibを追加すると認識してくれない時

VSCodeでRustを書いているのですが、libを追加して、それをmain.rs関数の中でuseしてもパスを認識してくれず、赤い波線が表示されてしまいます。rustのコンパイルは通るので文法は間違っていないはずです。

Must reload VSCode window after adding lib.rs to binary project to resolve `use` · Issue #715 · rust-lang/rls-vscode · GitHub
ここに現象についての記述がありました。

再現手順

  1. プロジェクトをcargo initを使って追加する
  2. その後、手動でlib.rsを追加する
  3. main.rsでlib.rsに追加したものをuseしようとする

と赤い波線が出現する

暫定対処方法

VSCodeのWindowをリロードする

やり方はcmd + shift + PでReloadを選択すればOKです。

他の対処方法?

vscodeのrls関連をアップデートする(これで解決するかは不明)

感想

とりあえず暫定的なやり方になってしまいましたが、libファイルは一回しか追加しないので何回もリロードし直すということもないので、ひとまずOKとしておきます。

Asembly Definition 試したけど体感が変わるほど、速くならなかった

Unityを2019.3系にアップデートしてからコンパイル時にレインボーが回るようになって、結構時間がかかるようになってしまいました。
そこでAssembly Definitionを利用すれば、コンパイル時間が速くなるというのを知ったので試してみました。

環境

  • Unity 2019.3.5
  • iMac 2019

目論見

Assembly Definitionを利用すればコンパイルを分割できるので、コンパイル時間を節約できる

実験

試しに一つのソースコードだけを特定のAssembly Definitionで管理するようにしました。

結果

このソースコードを修正した場合は1ソースコード分のコンパイルしか行われないので、めちゃくちゃ速くなるのではと思いましたが、体感は変わらず、相変わらずMacのレインボーが回ったままでした。

感想

体感スピードが変わらなくて、とても残念・・・
Unityを2019.3系にあげるまではここまで遅くなかったので、なんかUnityの問題なような気がしてきました。(想像です。)

「Curl error 56: Receiving data failed with unitytls error code 1048578」 がUnityででる

Curl error 56: Receiving data failed with unitytls error code 1048578

がでるようになりました。

https://forum.unity.com/threads/crashes-unity-with-curl-error-56-receiving-data-failed-with-unitytls-error-code-1048578.795066/

このフォーラムに同様の現象がありました。

環境

2019.2.16f

影響

特にエラーが出ても何も影響はありません。(実害なし)

解決方法

原因は不明なのですが、最近Unityを2019.3.5fに上げてから一回も見てませんのでUnityのバージョンアップで解決しました。

もやっとしますが、これで良しとします。

(定期的にこのエラーの現象が出現しているような気がします・・・)

Unity: RectTransformの変更を検知するためにUniRxのOnRectTransformDimensionsChangeAsObservableを使えば便利だった

特定のuGUIのRectTransformのサイズが変わった時に連動して何かしたい場合に、どうすればベストなのか調べていたら、UniRxのOnRectTransformDimensionsChangeAsObservableを使えば良いことたどり着きました。

RectTransformの値変更を検知する

[Unity]uGUIでRectTransfromが確定したときに何かしたい…みたいな話|杏z学習帳
このサイトによるとUniRxを使えば検知できるとのことだったので、早速調べてみると以下のようにすればOKでした
後述しますが、以下の2点が注目点です。

  • AddToは不要(自動破棄のため)
  • ObservableEventTrigger(uGUI用)なのでObservableTriggers系のAddComponentは必要
using UniRx;
using UniRx.Triggers;

void Awake()
    {
        var trigger = gameObject.AddComponent<ObservableRectTransformTrigger>();
        trigger.OnRectTransformDimensionsChangeAsObservable().Subscribe(
            Handler
        );
        void Handler(Unit unit) {
            // 何かの処理
        }
    }

ObservableTriggers

neue cc - UniRx 4.8 - 軽量イベントフックとuGUI連携によるデータバインディング
ObservableTriggersに色々イベントを検知できるみたいです。以下抜粋です。

  • ObservableMonoBehaviour は非推奨 (旧式)
  • Triggerは対象GameObjectがDestroyされると、OnCompletedを流してイベント発火を終了する
  • UniRx.Triggersをusingしている場合は、XxxAsObservableメソッドを直接拡張メソッドから呼べる (自動でAddComponetしてくれるのでAddComponentしなくても良い)
  • ObservableEventTrigger(uGUI用)とObservableStateMachineTrigger(Animation用)だけは自動付与がないので、これらの場合だけ自分で意識的に付与する必要がある

感想

Updateで監視するのは嫌だったので見つけれてよかった!

Rust: gitのincludeIfで設定したgitconfigがCargo newで生成されるCargo.tomlに反映されない

現象

includeIfをしようしてgitconfigを切り替えている場合に、cargo new <プロジェクト名>をするとCargo.tomlのauthorsに切り替えたgitconfigの情報が入らずに、globalで設定しているgitconfig情報が入ってしまう。

例えばglobalのgitconfigの設定が
username: global_takoyaki

includeIfで設定したgitconfigの設定が
username: local_takoyaki

とした場合に、切り替わるはずのディレクトリでcargo new <プロジェクト名>をするとglobal_takoyakiが設定されてしまう。
local_takoyakiにしたい!

追跡

GitHub - rust-lang/cargo: The Rust package manager
ここからCargoのRepoがあるので追跡してみる。
src/cargo/ops配下にCargoのコマンドのファイルがあります。
src/cargo/ops/cargo_new.rs
にはcargo newとcargo initのコマンド記述があります。

これらのメソッドは共通して

fn mk(config: &Config, opts: &MkOptions<'_>) -> CargoResult<()>

を呼び出しており、ここでgit initやCargo.tomlの一連の処理を行なっているようです。

特にgit initの処理は

fn init_vcs(path: &Path, vcs: VersionControl, config: &Config) -> CargoResult<()>

を呼び出しており、そこからバージョン管理のツールごとに場合分けを行なっています。

Gitの処理はsrc/cargo/util/vcs.rsのGitRepo構造体で管理されており、実態はlibgit2 for Rustが使用されているようです。

gitのincludeIfの仕様

対象のフォルダへ行ってgit config user.nameを実行しただけでは、globalのgitconfigが参照される。
git initをして、gitリポジトリが生成されてからgit config user.nameを実行するとincludeIfのgitconfigが参照される。

gitのincludeIfで指定したgitconfigが反映されない理由

原因はgitが生成されるディレクトリからgitconfigを取得しようとしていないためです。
例えば、takoyakiフォルダでCargo new <プロジェクト名>とした時の現在のディレクトリはtakoyakiなので、gitはtakoyakiフォルダにgitがないのでグローバルの設定を取得しにいこうとします。

かなり雑にCargoのソースコード修正

impl GitRepo {
    pub fn init(path: &Path, _: &Path) -> CargoResult<GitRepo> {
        let _ = env::set_current_dir(path).is_ok(); // <=====ここ
        git2::Repository::init(path)?;
        Ok(GitRepo)
    }
   // 省略
}
 let _ = env::set_current_dir(path).is_ok();

git initの処理される前に、現在の作業ディレクトリをgitが生成されるディレクトリに変更すれば、includeIfで設定したgitconfigが反映されます。

※ かなり雑です。何も考慮してません。

代替案

mkdir sample
cd sample
cargo init .

でcargo initを使用する方法ならgitの生成されるディレクトと作業ディレクトリが一致するので、想定のgitconfigの情報が反映されます。

修正すべきか?

微妙な気がします。
一応cargoのヘルプをみると以下のように記載されていて、

USAGE:
    cargo new [OPTIONS] <path>

OPTIONS:
    -q, --quiet                  No output printed to stdout
        --registry <REGISTRY>    Registry to use
        --vcs <VCS>              Initialize a new repository for the given version control system (git, hg, pijul, or
                                 fossil) or do not initialize any version control at all (none), overriding a global
                                 configuration. [possible values: git, hg, pijul, fossil, none]
        --bin                    Use a binary (application) template [default]
        --lib                    Use a library template
        --edition <YEAR>         Edition to set for the crate generated [possible values: 2015, 2018]
        --name <NAME>            Set the resulting package name, defaults to the directory name
    -v, --verbose                Use verbose output (-vv very verbose/build.rs output)
        --color <WHEN>           Coloring: auto, always, never
        --frozen                 Require Cargo.lock and cache are up to date
        --locked                 Require Cargo.lock is up to date
        --offline                Run without accessing the network
    -Z <FLAG>...                 Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details
    -h, --help                   Prints help information

ARGS:
    <path>

と書いてあるので、大丈夫と言えば、大丈夫なのですが、意識しないと、うっかりとglobalの方のgitconfigがtomlに反映されてしまうので、個人的には自動でincludeIfで設定したgitconfigを参照してほしい気がします。