Hello. Not right away, but I loved Rust. And this love led me to the endless seas of the lawless code. About what I managed to find - under the cut.
Secret data type
If you've read the Rust Book, you probably remember a similar snippet code:
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);
})
];
, , , ? . , . , .
Rust, good as it is, can be thought-provoking at times. Why doesn't retain change capacity? Why was functional calculus made lazy? Why does cargo create strange folders with hashes for every occasion, instead of building the same libraries once (although, in fairness, this is not a problem of the language itself)? Be that as it may, if writing on pluses is to shoot yourself in the foot, then writing on a rast is to try to shoot yourself in the foot (and God forbid you use ffi in the project, then attempts may be quite successful).
The purpose of this article is to try to delve deeply into the language, to understand how it works from the inside, because, as you know, you can only love someone you understand.