rustでopensslをbuildうまくできないときの対処法
みなさんこんにちは、エルゴヒューマンの椅子をかって腰の調子がすこぶる良い今日この頃です。
さて本題に入りましょう。 現在、統計的機械学習を学ぶためにRustでPRMLに乗っている手法を実装しているのですが、そこではもちろん行列計算や線形代数のツールを使う必要があります。私はrust-ndarrayを利用しています。線形代数を扱うndarray-linalgでは、intel-mklやopenblasなどを用いています。
そこで私のlinuxのマシンでbuildを行ったところ、
--- stderr thread 'main' panicked at ' Could not find directory of OpenSSL installation, and this `-sys` crate cannot proceed without this knowledge. If OpenSSL is installed and this crate had trouble finding it, you can set the `OPENSSL_DIR` environment variable for the compilation process. Make sure you also have the development packages of openssl installed. For example, `libssl-dev` on Ubuntu or `openssl-devel` on Fedora. If you're in a situation where you think the directory *should* be found automatically, please open a bug at https://github.com/sfackler/rust-openssl and include information about your system as well as this message. $HOST = x86_64-unknown-linux-gnu $TARGET = x86_64-unknown-linux-gnu openssl-sys = 0.9.60
このようなエラーを吐いてとまりました。 そこで、エラーの中身を見てみると、opensslがうまく入っていないようです。
OPENSSL_DIR
がうまく設定されていない可能性- libssl-devが入っていない可能性
があるように感じました。 そこで最初に
openssl version -a
してopensslの状態を調べます。 その結果
OpenSSL 1.1.1f 31 Mar 2020 built on: Mon Apr 20 11:53:50 2020 UTC platform: debian-amd64 options: bn(64,64) rc4(16x,int) des(int) blowfish(ptr) compiler: gcc -fPIC -pthread -m64 -Wa,--noexecstack -Wall -Wa,--noexecstack -g -O2 -fdebug-prefix-map=/build/openssl-P_ODHM/openssl-1.1.1f=. -fstack-protector-strong -Wformat -Werror=format-security -DOPENSSL_TLS_SECURITY_LEVEL=2 -DOPENSSL_USE_NODELETE -DL_ENDIAN -DOPENSSL_PIC -DOPENSSL_CPUID_OBJ -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DKECCAK1600_ASM -DRC4_ASM -DMD5_ASM -DAESNI_ASM -DVPAES_ASM -DGHASH_ASM -DECP_NISTZ256_ASM -DX25519_ASM -DPOLY1305_ASM -DNDEBUG -Wdate-time -D_FORTIFY_SOURCE=2 OPENSSLDIR: "/usr/lib/ssl" ENGINESDIR: "/usr/lib/x86_64-linux-gnu/engines-1.1" Seeding source: os-specific
と出てきたので、このパスを~/.zshrc
に書き加えました。
でも解決しませんでした。
そこで、libssl-devがうまく入っていない可能性があると思い、
sudo apt-get install libssl
しました。
Reading package lists... Done Building dependency tree Reading state information... Done E: Unable to locate package libssl-dev
ですが、うまく入らず。
となりうまく入らず... そこでいろいろ調べてみた結果、
/etc/apt/sources.list
に問題がありそうなことがわかりました。
で、sources.listとは何かといいますと、
に詳しく書いてあります。 これを、
に従って改変し、
sudo apt update sudo apt upgrade
したらうまく入りました。
WindowsのzipファイルをUbuntuで開くと文字化けしてしまう場合の対処法
unzip -O sjis **.zip
でやってもうまく行かない場合、
unzip -Ocp932 **.zip
でどうにかなる
dieselが大量のエラーを掃き出してインストールされないときの対処方
問題
dieselのチュートリアルの通りにインストールしようとした。 コマンドは
cargo install diesel_cli --no-default-features --features postgres
これでインストールしようとすると、大量のエラー
error: linking with `cc` failed: exit code: 1 | = note: "cc" "-Wl,--as-needed" "-Wl,-z,noexecstack" "-m64" "-Wl,--eh-frame-hdr" "-L" "/home/hikarukondo/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "/tmp/cargo-installl7MMnA/release/deps/diesel-f9383feb9231cfae.diesel.3yhc16ed-cgu.0.rcgu.o" "/tmp/cargo-installl7MMnA/release/deps/diesel-f9383feb9231cfae.diesel.3yhc16ed-cgu.1.rcgu.o" "/tmp/cargo-installl7MMnA/release/deps/diesel-f9383feb9231cfae.diesel.3yhc16ed-cgu.10.rcgu.o" "/tmp/cargo-installl7MMnA/release/deps/diesel-f9383feb9231cfae.diesel.3yhc16ed-cgu.11.rcgu.o" "/tmp/cargo-installl7MMnA/release/deps/diesel-f9383feb9231cfae.diesel.3yhc16ed-cgu.12.rcgu.o" "/tmp/cargo-installl7MMnA/release/deps/diesel-f9383feb9231cfae.diesel.3yhc16ed-cgu.13.rcgu.o" "/tmp/cargo-installl7MMnA/release/deps/diesel-f9383feb9231cfae.diesel.3yhc16ed-cgu.14.rcgu.o" "/tmp/cargo-installl7MMnA/release/deps/diesel-f9383feb9231cfae.diesel.3yhc16ed-cgu.15.rcgu.o" "/tmp/cargo-installl7MMnA/release/deps/diesel-f9383feb9231cfae.diesel.3yhc16ed-cgu.2.rcgu.o" "/tmp/cargo-installl7MMnA/release/deps/diesel-f9383feb9231cfae.diesel.3yhc16ed-cgu.3.rcgu.o" "/tmp/cargo-installl7MMnA/release/deps/diesel-f9383feb9231cfae.diesel.3yhc16ed-cgu.4.rcgu.o" "/tmp/cargo-installl7MMnA/release/deps/diesel-f9383feb9231cfae.diesel.3yhc16ed-cgu.5.rcgu.o" "/tmp/cargo-installl7MMnA/release/deps/diesel-f9383feb9231cfae.diesel.3yhc16ed-cgu.6.rcgu.o" "/tmp/cargo-installl7MMnA/release/deps/diesel-f9383feb9231cfae.diesel.3yhc16ed-cgu.7.rcgu.o" "/tmp/cargo-installl7MMnA/release/deps/diesel-f9383feb9231cfae.diesel.3yhc16ed-cgu.8.rcgu.o" "/tmp/cargo-installl7MMnA/release/deps/diesel-f9383feb9231cfae.diesel.3yhc16ed-cgu.9.rcgu.o" "-o" "/tmp/cargo-installl7MMnA/release/deps/diesel-f9383feb9231cfae" "/tmp/cargo-installl7MMnA/release/deps/diesel-f9383feb9231cfae.2ljx8vxpfob2gs4q.rcgu.o" "-Wl,--gc-sections" "-pie" "-Wl,-zrelro" "-Wl,-znow" "-Wl,-O1" "-nodefaultlibs" "-L" "/tmp/cargo-installl7MMnA/release/deps" "-L" "/usr/lib/x86_64-linux-gnu" "-L" "/home/hikarukondo/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bstatic" "/tmp/cargo-installl7MMnA/release/deps/liburl-467eaddfcce53554.rlib" "/tmp/cargo-installl7MMnA/release/deps/libpercent_encoding-6404fa3895139f99.rlib" "/tmp/cargo-installl7MMnA/release/deps/libidna-1cf68800b7ed22b1.rlib" "/tmp/cargo-installl7MMnA/release/deps/libunicode_normalization-65fa459eef99a4b7.rlib" "/tmp/cargo-installl7MMnA/release/deps/libtinyvec-3c50fc017bbed66b.rlib" "/tmp/cargo-installl7MMnA/release/deps/libunicode_bidi-d7adc887995a8f0b.rlib" "/tmp/cargo-installl7MMnA/release/deps/libmatches-389a53a8d07e8373.rlib" "/tmp/cargo-installl7MMnA/release/deps/libtoml-2f55c3bb86f27f38.rlib" "/tmp/cargo-installl7MMnA/release/deps/libtempfile-e18b97729444a80f.rlib" "/tmp/cargo-installl7MMnA/release/deps/librand-2a54687171897a17.rlib" "/tmp/cargo-installl7MMnA/release/deps/librand_chacha-611571fee6109426.rlib" "/tmp/cargo-installl7MMnA/release/deps/libppv_lite86-7acc70b7fe3e6300.rlib" "/tmp/cargo-installl7MMnA/release/deps/librand_core-dd9c19cb313f4f24.rlib" "/tmp/cargo-installl7MMnA/release/deps/libgetrandom-3493a36dcbda61cc.rlib" "/tmp/cargo-installl7MMnA/release/deps/libremove_dir_all-e105efd57f3eec17.rlib" "/tmp/cargo-installl7MMnA/release/deps/libcfg_if-0f89700f04afbfc5.rlib" "/tmp/cargo-installl7MMnA/release/deps/libserde-3465af54848603e5.rlib" "/tmp/cargo-installl7MMnA/release/deps/libmigrations_internals-239d6c6fa4d17fa3.rlib" "/tmp/cargo-installl7MMnA/release/deps/libdotenv-8bb50913892f7b18.rlib" "/tmp/cargo-installl7MMnA/release/deps/libregex-a4a15eaf73f6b450.rlib" "/tmp/cargo-installl7MMnA/release/deps/libutf8_ranges-24dc3098c5a9996e.rlib" "/tmp/cargo-installl7MMnA/release/deps/libregex_syntax-c181b1c5b45966ed.rlib" "/tmp/cargo-installl7MMnA/release/deps/libucd_util-3a31297ed9e71b37.rlib" "/tmp/cargo-installl7MMnA/release/deps/libthread_local-7f22dce31c3b8610.rlib" "/tmp/cargo-installl7MMnA/release/deps/liblazy_static-a2d4e9568ec6e14c.rlib" "/tmp/cargo-installl7MMnA/release/deps/libaho_corasick-1f870e1cc8698ef1.rlib" "/tmp/cargo-installl7MMnA/release/deps/libmemchr-ad18c58549176d99.rlib" "/tmp/cargo-installl7MMnA/release/deps/liberror_chain-07208c47f3f894a2.rlib" "/tmp/cargo-installl7MMnA/release/deps/libbacktrace-4f92aa72f2665e9a.rlib" "/tmp/cargo-installl7MMnA/release/deps/libminiz_oxide-832fc9383d1c709f.rlib" "/tmp/cargo-installl7MMnA/release/deps/libadler-db4c0f56e21a0544.rlib" "/tmp/cargo-installl7MMnA/release/deps/libobject-ff42ba3d842bf54f.rlib" "/tmp/cargo-installl7MMnA/release/deps/libaddr2line-49fa3ae780197da5.rlib" "/tmp/cargo-installl7MMnA/release/deps/libgimli-bdcfc0588434ee82.rlib" "/tmp/cargo-installl7MMnA/release/deps/libcfg_if-6d7e6186e726238c.rlib" "/tmp/cargo-installl7MMnA/release/deps/librustc_demangle-759799f7a70b78ca.rlib" "/tmp/cargo-installl7MMnA/release/deps/libdiesel-deb5637a5f67f223.rlib" "/tmp/cargo-installl7MMnA/release/deps/libpq_sys-86aaf66686c5e02e.rlib" "/tmp/cargo-installl7MMnA/release/deps/libbyteorder-eb338c1472124957.rlib" "/tmp/cargo-installl7MMnA/release/deps/libclap-1df416366c8280d8.rlib" "/tmp/cargo-installl7MMnA/release/deps/libvec_map-405e6da89d886d17.rlib" "/tmp/cargo-installl7MMnA/release/deps/libtextwrap-ab9ff3722de2db3a.rlib" "/tmp/cargo-installl7MMnA/release/deps/libunicode_width-5f4356788e200ee8.rlib" "/tmp/cargo-installl7MMnA/release/deps/libstrsim-4674324dc7d46173.rlib" "/tmp/cargo-installl7MMnA/release/deps/libbitflags-ff7f5482904c4de3.rlib" "/tmp/cargo-installl7MMnA/release/deps/libatty-77e74e8a1493e544.rlib" "/tmp/cargo-installl7MMnA/release/deps/libansi_term-51c4c3bdcd4f8b68.rlib" "/tmp/cargo-installl7MMnA/release/deps/libchrono-dadbce334e241555.rlib" "/tmp/cargo-installl7MMnA/release/deps/libnum_integer-68daeca7f4931930.rlib" "/tmp/cargo-installl7MMnA/release/deps/libnum_traits-57b35a11280e5fc4.rlib" "/tmp/cargo-installl7MMnA/release/deps/libtime-18a87bf33e135542.rlib" "/tmp/cargo-installl7MMnA/release/deps/liblibc-171b7f68884a56a2.rlib" "-Wl,--start-group" "/home/hikarukondo/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-f14aca24435a5414.rlib" "/home/hikarukondo/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-48d342a8b48d1d01.rlib" "/home/hikarukondo/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libminiz_oxide-14bc0820888c8eb3.rlib" "/home/hikarukondo/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libadler-9cbd9e217bff06bc.rlib" "/home/hikarukondo/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libobject-31826136df98934e.rlib" "/home/hikarukondo/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libaddr2line-075976a117c8fd5d.rlib" "/home/hikarukondo/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libgimli-2d5cbedfbf17a011.rlib" "/home/hikarukondo/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_demangle-0474372ff08c5319.rlib" "/home/hikarukondo/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libhashbrown-d437c34460d2315a.rlib" "/home/hikarukondo/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_alloc-fb61ed1b8cc4de79.rlib" "/home/hikarukondo/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-bf76d1b643bfc9f0.rlib" "/home/hikarukondo/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcfg_if-a1b53aa7fddcf418.rlib" "/home/hikarukondo/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-28585e57fac45c73.rlib" "/home/hikarukondo/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-64801769bc15ab28.rlib" "/home/hikarukondo/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_core-541997b56bb98660.rlib" "/home/hikarukondo/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-cdea3c81adab3d12.rlib" "-Wl,--end-group" "/home/hikarukondo/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-cd9f15a39fb65cbc.rlib" "-Wl,-Bdynamic" "-lpq" "-ldl" "-lrt" "-lpthread" "-lgcc_s" "-lc" "-lm" "-lrt" "-lpthread" "-lutil" "-ldl" "-lutil" = note: /usr/bin/ld: cannot find -lpq collect2: error: ld returned 1 exit status error: aborting due to previous error error: failed to compile `diesel_cli v1.4.1`, intermediate artifacts can be found at `/tmp/cargo-installl7MMnA` Caused by: could not compile `diesel_cli`. To learn more, run the command again with --verbose.
対処方 githubのissueに記載があった。
sudo apt install libpq-dev
で解決した。
DMPfold
DMPfoldに関しての備忘録です。
概要
- 距離マップの予測とモデルの生成を2ステップに行うのではなく、イテレーティブに行った。
- コンタクトマップの予測ではなく、距離マップの予測を行う。
- Pfam, CASP12, 膜貫通タンパク質に対して従来手法と比較し高精度に予測できた。
結果
上の図はDMPfoldの生成モデルの概要です。 aはCASP12 FMドメインのモデル、bはFILM3のモデル、cはPfamの構造が判明しているもの。dはCASP13FMのターゲットです。
にCASP12の主要モデルとの比較を掲載します。 TM-scoreが他のモデルと比較して高いことがわかります。 Rosetta-2000は良いTM-scoreであるが、どのモデルが高いTM-scoreかわからないため使いづらいです。 その一方でDMPfoldは少ないモデルでも高いTM-scoreを出すため、使いやすいモデルであると言えます。
また、CASP12の主要な手法とのTM-scoreの分布をaに示します。 この図から分かるように他の手法と比較して、TM-scoreの分布が高い方向になっています。 また、bには、CONFOLD2と比較、cはROSETTAとの比較です。 さらにcはイテレーションの回数によるTM-scoreの変動を表しています。
この図から分かるように、イテレーションを行うことでTM-scoreが上昇しています。
https://www.nature.com/articles/s41467-019-11994-0/figures/3
これは膜タンパク質に対しての結果です。 TM-scoreの分布をみると既存手法に比べて高くなっていることがわかります。
Pfamに対する結果です。 Pfamの結果既存手法に対しても良い。 ここに関しては完全に理解できなかった。
イテレーションによる距離マップの精度の比較。
アライメントの質とTM-scoreの関係とタンパク質配列とTM-scoreの関係 配列の長さとTM-scoreには相関がないことがわかる。 また、アライメントが深い方が良い精度予測できる傾向にある。
実験方法
DMPfoldの予測の手順。 距離マップ、水素結合、ねじれ角をネットワークを用いて予測し、CNSを用いてモデルを作成する。
それぞれを予測する際のネットワークの構造。 aは距離マップを予測するネットワーク。bは水素結合を予測するネットワーク。cはねじれ角を予測するネットワーク。
距離マップは回帰問題では無く、分類問題として解かれる。 距離マップはシンメトリーである必要があるため、そうなるように処理している。
水素結合のネットワークは、横はアクセプター、縦はドナーの尤度を表している。
また、ねじれ角のモデルは、LSTM層を用いることで3次元のテンソルを2次元の行列に変換し予測を行っている。
CNSを用いた予測について。 何もわからn
Rust Tips
Rustlangのtipsに関して書いていきます。 随時更新します。 完全にメモです。俺以外が見ても意味ないです。
現在、rust勉強中です。 まさかり投げないで間違ってたら優しく教えてください。 すぐに訂正いたします。 ご指摘お待ちしてます。
Json
extern crate serde_json;
でインポートして、使い方は、
Value
型の変数にfrom_str
とかでjson型のデータを保持できる。
extern crate serde_json; extern crate serde_json::{Result, Value}; use serde_json::{Result, Value}; fn untyped_example() -> Result<()> { // Some JSON input data as a &str. Maybe this comes from the user. let data = r#" { "name": "John Doe", "age": 43, "phones": [ "+44 1234567", "+44 2345678" ] }"#; // Parse the string of data into serde_json::Value. let v: Value = serde_json::from_str(data)?; // Access parts of the data by indexing with square brackets. println!("Please call {} at the number {}", v["name"], v["phones"][0]); Ok(()) }
あとは、任意の構造体に対してjsonにパースする方法。
use serde::{Deserialize, Serialize}; use serde_json::Result; #[derive(Serialize, Deserialize)] struct Address { street: String, city: String, } fn print_an_address() -> Result<()> { // Some data structure. let address = Address { street: "10 Downing Street".to_owned(), city: "London".to_owned(), }; // Serialize it to a JSON string. let j = serde_json::to_string(&address)?; // Print, write to a file, or send to an HTTP server. println!("{}", j); Ok(()) }
エラー関係
.unwrap()
Option<T>
のやつみたいな感じ。
None
だった時にpanic
する。
なんかpanic
やたらめったらされたら怖いから普通にmatch
で実装した方がいいと思うけど、簡単な実装なら便利そう。
?
doc.rust-lang.org
pythonでいうところのtry
。
before lib.rs
fn read_username_from_file() -> Result<String, io::Error> { let f = File::open("username.txt"); let mut f = match f { Ok(file) => file, Err(e) => return Err(e), }; let mut s = String::new(); match f.read_to_string(&mut s) { Ok(_) => Ok(s), Err(e) => Err(e), } }
after lib.rs
fn read_username_from_file() -> Result<String, io::Error> { let mut f = File::open("username.txt")?; let mut s = String::new(); f.read_to_string(&mut s)?; Ok(s) }
こんな感じ。
このコードはstd::fs::read_to_string
で一発で使える。
try!(try!(try!(foo()).bar()).baz())
を
foo()?.bar()?.baz()?
に省略できる。
エラーならErr
をreturn
してくれるっぽい。
#[derive(Debug)]
例えば、構造体
struct User { name: String, ange: u32, }
このような構造体に対して、中身を出力しようとすると、
let BoKuToTsuZenU = User { name: String::from("BoKuToTsuZenU"), age: 100000}; println!("創造神冒頓単于のスペックワロタwwwwwwww{}", BoKuToTsuZenU);
こうすると、 エラーでます。 解決策は、
#[derive(Debug)] struct User { name: String, age: u32 } fn main() { let BoKuToTsuZenU = User {name: String::from("BoKuToTsuZenU"), age: 100000}; println!("{:?}", BoKuToTsuZenU); }
これで動きます。または、{:#?}
だとさらに見やすいかもしれない。
構造体のメソッド記法
struct User { name: String, age: u32 } impl User { fn is_adult(&self) -> bool { if self.age > 20 { true } else { false} } } fn main() { let god = User{name: String::from("BoKuToTsuZenU"), age: 10000}; let adult = god.is_adult(); if adult { println!("{} is adult", god.name); } else { println!("{} is not adult", god,name); } }
見たい感じ。詳しいことはここをクリック!!!!
Rustのライフタイムについて
rustにはライフタイムという概念があります。みんなひっかかると思いますが、私も引っかかりました。。。
自分用のメモなのでわかりづらくても悪しからず。
ライフタイム
ライフタイムとは、参照が有効なスコープのことです。 rustではスコープを抜けるとメモリが開放されます。例えば、
変数x
、y
のライフタイムは
fn main() { let x = String::from("HogeHoge"); // x ここから { let y = String::from("fugafuga"); // y ここから } // y ここまで println!("{}",y); }// x ここまで
こうなるのは他の言語でもよくあることだと思います。 そこで、rustでは開放されたメモリポインタ(ダングリングポインタ)にアクセスしたり参照できないようになっています。 rustのコンパイラには借用チェッカーが存在しています。 これが、ダングリングポインタを参照しないようにしています。
基本的に参照全てにライフタイムを考える必要があります 例外を最後の方に示します。
借用チェッカー
長い文字列を変換する関数longest
に関して、
fn longest(x: &String, y: &String) -> &String { if x.len() > y.len() { x } else { y } } fn main() { let x = String::from("BoKuToTsuZenU"); let y = String::from("Tohoku Univ"); let longer = longest(x, y); }
これはエラーになります。
Compiling rust_test v0.1.0 (/Users/hikarukondo/Documents/rust/rust_test) error[E0106]: missing lifetime specifier --> src/main.rs:1:39 | 1 | fn longest(x: &String, y: &String) -> &String { | ------- ------- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` help: consider introducing a named lifetime parameter | 1 | fn longest<'a>(x: &'a String, y: &'a String) -> &'a String { | ^^^^ ^^^^^^^^^^ ^^^^^^^^^^ ^^^ error: aborting due to previous error For more information about this error, try `rustc --explain E0106`. error: could not compile `rust_test`. To learn more, run the command again with --verbose.
これでエラーになる理由は、戻り値の参照がx,y
になるか、コンパイラが判別できないため、戻り値がどちらのライフタイムになるかわからないからです。
ライフタイム引数の記法
この問題を解決するため、参照間の関係を定義するライフタイム引数を用います。
rustのライフタイム引数の定義の仕方は'a
みたいな感じで書きます。
ライフタイム引数を持つ関数
同じライフタイム引数では同じライフタイムを持つものとしてコンパイルされます。
longest
関数の入力は同じライフタイムを持つものとして同じライフタイム引数を使用します。
fn longest<'a>(x: &'a String, y: &'a String) -> &'a String { if x.len() > y.len() { x } else { y } } fn main() { let x = String::from("BoKuToTsuZenU"); let y = String::from("Tohoku Univ"); let longer = longest(x, y); }
こんな感じでライフタイム引数で修飾するとコンパイルできます。
ジェネリックなライフタイム'a
は、x
とy
のライフタイムのうち、小さい方に等しい具体的なライフタイムになります。
fn longest<'a>(x: &'a String, y: &'a String) -> &'a String { if x.len() > y.len() { x } else { y } } fn main() { let x = String::from("BoKuToTsuZenU"); let longer; { let y = String::from("Tohoku Univ"); longer = longest(x, y); } println!("{}", longer); }
このコードはエラーになります。
なぜなら、戻り値のライフタイムは入力のライフタイムの短い方になるからです。
つまり、戻りのライフタイムはy
のライフタイムと同じです。
そのため、エラーが起こります。
以降は追記します。
構造体のライフタイム
まずこのコードを見てください。
struct User { username: &str, email: &str, sign_in_count: u64, active: bool, } fn main() { let user1 = User { email: "someone@example.com", username: "someusername123", active: true, sign_in_count: 1, }; }
これはエラーを吐きます。構造体の要素に参照を持つことも可能ですが、ライフタイムの注釈が必要です。
struct User<'a> { username: &'a str, email: &'a str, sign_in_conunt: u64, active:bool }
で宣言することが可能です。
ライフタイム引数を持つ構造体のメソッド
impl<'a> User<'a> { fn somefunc(&self, T){ /* do something */} }
のように宣言すればできます。
ライフタイムの省略
rustのライフタイムは元々全ての関数で書く必要があったらしいです。 ですが、数多くのコードを解析した結果一意にライフタイムを推定できる場合にはライフタイムの省略することが可能になりました。
ライフタイムの省略には規則があります(参照)。 コンパイラが以下の規則を用いてライフタイムを推定できない参照が存在する場合エラーになります。
入力に対して:参照である各引数は、独自のライフタイム引数を得る。
fn somefunc<'a>(x: &'a str)
や、fn somefunc<'a, 'b>(x: &'a str, y; &'b str)
など。 それぞれの引数に対して別々のライフタイムを与えるということだと思います。1つだけ入力ライフタイム引数があるなら、そのライフタイムが全ての出力ライフタイム引数に代入される
fn somefunc<'a>(x: &'a str) -> &'a str
みたいな場合。複数の入力ライフタイム引数があるけれども、メソッドなのでそのうちの一つが
&self
や&mut self
だったら、self
のライフタイムが全出力ライフタイム引数に代入される
例題
fn first_word(s: &str) -> &str { let bytes = s.as_bytes(); for (i, &item) in bytes.iter().enumerate() { if item == b' ' { return &s[0..i]; } } &s[..] }
上記のコードは動作します。 参照を引数にとり、参照を戻り値にしています。なぜ、コンパイルできるのでしょうか?
私たちはコンパイラ様のお気持ちを考える必要があります。
まず最初の規則参照である各引数は、独自のライフタイム引数を得る
を適応します。
つまり、引数は全部独自のライフタイムをうけるとします。
今回は一つしか引数がないのでこの関数のシグニチャは以下のようになります。
fn first_word<'a>(s: &'a str) -> &str{ /* do something */}
次に、二つ目の引数に対してです。
この関数の引数は一つなので、適応できて、fn fiet_word<'a>(s: &'a str) -> &'a str {/* do something */}
これにてめでたく、入出力に関してライフタイムは全て推測することができました。
次の例題です。
fn longest(x: &str, y: &str) -> &str { if x.len() > y.len() { x } else { y } }
これに対しても同じように考えましょう。
まず第一の規則を適応してfn longest<'a,'b>(x: &'a str, y: &'a str) -> &str
次にこの関数の引数は二つのため、出力のライフタイムを推測することはできません。
さらに、第三の規則は全く関係ないので、出力の参照のライフタイムを推定することができません。
そのためこのシグニチャではコンパイラ様はライフタイムを推定できないのでエラーです。
静的ライフタイム
'static
で宣言できる。 この宣言の参照はプログラムの全期間を表している。
まとめ
これからもrustのコンパイラとの戦いは続きそうです。 困ったらここを見よう