雑なメモ書き

気楽にいきます

Rustの構造体に対する疑問を検証してみた

doc.rust-lang.org

こちらのドキュメントに対する疑問を解消しております。

構造体に初期値が勝手に入るか?

  • ここの構造体の説明で初期値が無いとどうなるか特に言ってない
  • おそらくはエラーになるはずだが
  • どんなメッセージだかは気になる
fn main() {
    #[derive(Debug)]
    struct User {
        username: String,
        email: String,
        sign_in_count: u64,
        active: bool,
    }

    let user1 = User {};
}

missing fieldsと言われてエラーになる

error[E0063]: missing fields `active`, `email`, `sign_in_count` and 1 other field in initializer of `main::User`
  --> src/main.rs:11:17
   |
11 |     let user1 = User {};
   |                 ^^^^ missing `active`, `email`, `sign_in_count` and 1 other field

error: aborting due to previous error

For more information about this error, try `rustc --explain E0063`.

この件でしらべてみたらでてきたstd::default::Defaultを使うといいらしい

www.utam0k.jp

Struct Update Syntaxというものがある

fn main() {
    #[derive(Debug)]
    struct User {
        username: String,
        email: String,
        sign_in_count: u64,
        active: bool,
    }

    let user1 = User {
        email: String::from("someone@example.com"),
        username: String::from("someusername123"),
        active: true,
        sign_in_count: 1,
    };

    let user2 = User {
        email: String::from("another@example.com"),
        username: String::from("anotherusername567"),
        ..user1
    };

    println!("{:?},{:?}",user1,user2)
}

よくこの構造体を見てほしい

struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

Struct Update Syntaxで扱われたデータは基本データ型のみではないだろうか?

let user2 = User {
    email: String::from("another@example.com"),
    username: String::from("anotherusername567"),
    ..user1
};

Struct Update SyntaxにCopyが実装されていないデータ型を渡すとどうなるのか?

let user2 = User {
    email: String::from("another@example.com"),
    //username: String::from("anotherusername567"),
    ..user1
};

user2の方へ所有権が移動した為user1が使えなくなり後ろのprintlnで怒られました

error[E0382]: borrow of moved value: `user1`
  --> src/main.rs:24:26
   |
18 |       let user2 = User {
   |  _________________-
19 | |         email: String::from("another@example.com"),
20 | |         //username: String::from("anotherusername567"),
21 | |         ..user1
22 | |     };
   | |_____- value moved here
23 | 
24 |       println!("{:?},{:?}",user1,user2)
   |                            ^^^^^ value borrowed here after partial move
   |
   = note: move occurs because `user1.username` has type `std::string::String`, which does not implement the `Copy` trait

GDB Documentationを読んで見る

www.gnu.org

  • GDBのドキュメントを頭からやっていこうかなという感じです

TOP Pageには何が書いてあるか

概ね以下のような内容です。

オンラインマニュアル

呼び出し方

  • ここに普段は使わないであろうオプションが見られます

shellコマンドの使用方法

  • 以下のように実行したいコマンドを
  • shellの後ろで打ちます
shell ls

ログの出力

ロギングを有効・無効

set logging on|off

ログファイルの名前を変更

set logging file file

debug出力の切り替え

set logging redirect [on|off]
set logging debugredirect [on|off]

現在の設定値を表示

show logging

コマンド

プログラムを実行

プログラムの開始

run

引数指定

set args

引数の確認

show args

あとで続きを書きます。

Rustのリテラル文字列はどういう扱いなのか?

参考

変な現象に遭遇する

  • まあ結果的に変じゃないんですけど
  • リテラルの文字列を扱うとエラーにならない
  • 所有権がmoveした物を使用したらこんぱいるできないんじゃないの?
fn main() {
    let s = "hello";
    let s2 = s;
    println!("{},{}",s,s2);
}
 cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.19s
     Running `target/debug/hello`
hello,hello

想定していた動作

fn main() {
    let s = String::from("hello");
    let s2 = s;
    println!("{},{}",s,s2);
}
  • これですよこのエラーが出るのを期待していたんですよ
 cargo run
   Compiling hello v0.1.0 (/data)
error[E0382]: borrow of moved value: `s`
 --> src/main.rs:4:22
  |
2 |     let s = String::from("hello");
  |         - move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
3 |     let s2 = s;
  |              - value moved here
4 |     println!("{},{}",s,s2);
  |                      ^ value borrowed here after move

error: aborting due to previous error

For more information about this error, try `rustc --explain E0382`.
error: could not compile `hello`.

To learn more, run the command again with --verbose.

そもそもの理解

  • String型はCopyトレイトを実装していない為
  • 別の変数にバインディングをした場合
  • バインディング先の変数へ所有権を移動させる
  • 所有権が移動した変数を参照することはできない

いま起きてて困っていること

  • Stringとstrが同一の挙動をすると思っていたら
  • strの方は所有権が移動せずエラーにならない

そして気づいた

f:id:hiroyukim:20200209100010p:plain

前者の文字列

後者の文字列

つまりこういうこと

objdumpのソースコードがUbuntuで欲しい

所属パッケージを探す

 dpkg -S objdump
zsh-common: /usr/share/zsh/functions/Completion/Unix/_objdump
binutils-common:amd64: /usr/share/man/man1/objdump.1.gz
binutils-x86-64-linux-gnu: /usr/share/man/man1/x86_64-linux-gnu-objdump.1.gz
binutils-x86-64-linux-gnu: /usr/bin/x86_64-linux-gnu-objdump
binutils: /usr/bin/objdump

所属パッケージのコードを落とす

apt source binutils

rustで所有権ぽいやつをコードで追ってみる

所有権の説明

doc.rust-lang.org

  • 本家を読むと出てくる
  • 以下の3つのルールが気になる訳です

Each value in Rust has a variable that’s called its owner. There can only be one owner at a time. When the owner goes out of scope, the value will be dropped.

  • 所有権という変数を保持しているという話になる
  • それぽいやつをコードを追うときに見てるので
  • 追ってみる

実行

簡単なプログラムを起動する

1 fn main() {
2      let mut s = String::from("hello");
3      s.push_str(", world");
4      println!("{}",s);
5  }

String::fromへstepin

  • 早速to_ownedというメソッドが出てきています。
2228  impl From<&str> for String {
2229       #[inline]
2230       fn from(s: &str) -> String {
2231           s.to_owned()
2232       }
2233   }
  • このメソッドは以下です

doc.rust-lang.org

Some types make it possible to go from borrowed to owned, usually by implementing the Clone trait. But Clone works only for going from &T to T. The ToOwned trait generalizes Clone to construct owned data from any borrow of a given type. Creates owned data from borrowed data, usually by cloning.

  • 内容的には特定の借用のときに使うぽい
202 #[stable(feature = "rust1", since = "1.0.0")]
203 impl ToOwned for str {
204     type Owned = String;
205     #[inline]
206     fn to_owned(&self) -> String {
207         unsafe { String::from_utf8_unchecked(self.as_bytes().to_owned()) }
208     }
209
210     fn clone_into(&self, target: &mut String) {
211         let mut b = mem::take(target).into_bytes();
212         self.as_bytes().clone_into(&mut b);
213         *target = unsafe { String::from_utf8_unchecked(b) }
214     }
215 }
  • このケースは明示的に書く必要があるんだろうな。
  • 後でまた戻ってくる。

Linuxでpasteコマンドとnlコマンドを使って行番号付きテーブルを作成する

  • こんにちは
  • 複数のファイルを合成してテーブルにするのを簡単にしたいので
  • そのときに使用したコマンドをまとめました

2つのファイルの合成

paste a b -d '|' > c

行番号の追加

nl c > d

markdownに書き出す際へのエスケープ処理

  • 他にもありますが
  • stactraceの場合はこれで一端すみました
ruby -i -pe '$_.gsub!("\|", "\\|")'

出力結果

  • こんな感じになります

f:id:hiroyukim:20200203123633p:plain