こんにちは。すぐにではありませんが、私はRustが大好きでした。そして、この愛は私を無法のコードの果てしない海へと導きました。私が何とか見つけたものについて-カットの下で。
シークレットデータ型
Rust Bookを読んだことがあるなら、おそらく同様のスニペットコードを覚えているでしょう。
fn unwrap<T>(option: Option<T>) -> T{
let unwrapped = match option{
Some(val) => val,
None => panic!("This cannot be None!")
};
return unwrapped;
}
fn main() {
let unwrapped = unwrap(Some(0));
}
もちろん、ここでは珍しいことは何もありません。Option内に値がある場合はそれを返すか、panic!マクロを使用してプロセス終了を呼び出します。しかし、なぜこのコードがコンパイルされるのか疑問に思ったことはありませんか?コンパイラは、Tを返す関数が...これを返すことができることをどのように知っていますか?
"!" . ? :
#![feature(never_type)]
use std::convert::TryInto;
#[derive(Debug)]
enum ConnectionError{
BrokenPipe,
BadId,
Other
}
struct Client;
struct Request;
struct Response;
impl Request{
pub fn build_response(&self) -> Response{
Response
}
}
fn get_request(id: i32) -> Result<(Client, Request), ConnectionError>{
match id % 2 == 0{
true => {
Ok((Client, Request))
},
false => {
Err(ConnectionError::BadId)
}
}
}
fn init_server() -> Result<!, ConnectionError>{
loop {
let (client, request) = get_request(5i32)?;
let resp = request.build_response();
};
}
fn main() {
let x: ! = init_server().unwrap();
}
, , nightly , "!" "()":
fn init_server() -> Result<(), ConnectionError>{
loop {
let (client, request) = get_request(5i32)?;
let resp = request.build_response();
};
}
fn main() {
let x = init_server().unwrap();
}
? , :
fn main() {
match init_server(){
Ok(v) => { println!("unreachable? {:?}", v); },
Err(_) => {}
};
}
, Ok(v) - . , , . , , , .
? , v
"". "!" , break
, continue
std::process::exit
.
, , . #![feature(never_type)]
? , , , . , , . panic, expect, todo unimplemented. "!"?
, . , .
Rust ( - , ) Fn
. - - ("closures" "", ), , . ?
, , , impl Trait. , , ...
use std::any::type_name;
fn type_of<T>(x: T) -> &'static str {
type_name::<T>()
}
fn callback() -> impl Fn(f32) -> f32{
|a| {
a*2.
}
}
fn main() {
let x = callback();
println!("{}", type_of(x));
}
: playground::callback::{{closure}}
. , , impl Fn(f32) -> f32
, , . , trait object, dyn. - , trait object, Box:
fn main() {
let x: Box<dyn Fn(f32) -> f32> = Box::new(callback());
println!("{}", type_of(x));
}
:
alloc::boxed::Box<dyn core::ops::function::Fn<(f32,)>+Output = f32>
: , , .
, :
use tokio; // 1.0.2
use tokio::task::JoinError;
use futures::prelude::*; // 0.3.12
async fn job1(){}
async fn job2(){
for i in 0..5{}
}
async fn job() -> Vec<impl Future<Output = Result<(), JoinError>>>{
vec![
tokio::spawn(async move{
job1().await;
}),
tokio::spawn(async move{
job2().await;
})]
}
#[tokio::main]
async fn main() {
let mut v = job();
}
, - tokio::spawn
tokio::task::JoinHandle
. , JoinHandle - , , async{}
, , async-, ?
let v = vec![
Box::new(async{}),
Box::new(async{
let cb = |x| x*2.;
let val = cb(1f32);
})
];
, , , ? . , . , .
さびは、それ自体が良いのですが、時には考えさせられることがあります。変更容量を保持しないのはなぜですか?汎関数計算が怠惰になったのはなぜですか?同じライブラリを一度構築するのではなく、貨物が毎回ハッシュ付きの奇妙なフォルダを作成するのはなぜですか(ただし、公平を期すために、これは言語自体の問題ではありません)。とはいえ、プラスに書くことが自分を足で撃つことである場合、ラストに書くことは自分を足で撃つことを試みることです(そして神はあなたがプロジェクトでffiを使用することを禁じています、そして試みはかなり成功するかもしれません) 。
この記事の目的は、言語を深く掘り下げて、言語がどのように機能するかを内部から理解することです。ご存知のように、あなたは理解している人しか愛せないからです。