⬆️ ⬇️

Is it so scary Rust, as it is painted

Some time ago, I began to understand the need to diversify my programming experience exclusively in C #. After some study of various options, such as Haskell, Scala, Rust and some others, the choice fell on the last one. Over time, I began to notice that Rust is increasingly being advertised solely as a "system language" that is needed for extremely complex compilers and super-loaded systems, with special security and multithreading requirements, and for simpler options there is Go / Python / Java / ..., while I gladly and quite successfully used it as a replacement for my workhorse C #.





In this article I wanted to tell why I consider this trend as a whole harmful, and why Rust is a good general-purpose language in which you can do any projects, starting with any microservices, and ending with the scripting of the daily routine.



Introduction



Why, in fact, learn a new language, the more difficult? It seems to me that the answer of the article “Overcoming Mediocrity” is the closest to the truth, namely:



Everyone knows that writing the entire program manually in machine language is wrong. But they understand much less often that there is a more general principle: in the presence of a choice of several languages, it is wrong to program on something other than the most powerful one, unless other reasons influence the choice.

The more complex the language, the richer the phrases composed with its help, and the better it can express the desired subject area. Since concepts are usually studied once, and are applied many times, much more profitable from the point of view of investing their own time to study all kinds of scary words like "monadic transformers" (and, preferably, their meaning), in order to save their mental forces and spend them nice And therefore, it is very sad to see the trend of some companies to make specially "simplified" languages. As a result, the vocabulary of these languages ​​is much smaller, and it is not difficult to learn it, but then reading the “my yours to buy onion” programs is very difficult, not to mention possible ambiguous interpretations.



The basics



As usual, a newbie gets to know a programming language? He goesogle the most popular book on the language, gets it, and starts reading. As a rule, it contains HelloWorld, a compiler installation instruction, and then basic information on the language with a gradual complication. In the case of rasta, this is a handpiece , and the first example is reading a number from the console and displaying it on the screen. How would we do this in the same C #? Well, probably something like that



var number = int.Parse(Console.ReadLine());
Console.WriteLine($"You guessed: {number}");


?



let mut guess = String::new();

io::stdin().read_line(&mut guess)
    .expect("Failed to read line");

let guess: u32 = guess.trim().parse()
    .expect("Please type a number!");

println!("You guessed: {}", guess);


, ( !), , .. " " "" .



:



let mut guess = String::new();
io::stdin().read_line(&mut guess)?;
let guess: u32 = guess.trim().parse()?;
println!("You guessed: {}", guess);


, , . , , . , , .



? - , , C# , , - .





.



fn search<F>(self, hash: u64, is_match: F, compare_hashes: bool)  
   -> RawEntryMut<'a, K, V, S>
  where for<'b> F: FnMut(&'b K) -> bool


, " ", " , ", " , GC ".



. , , . :



  • Each elided lifetime in input position becomes a distinct lifetime parameter.
  • If there is exactly one input lifetime position (elided or not), that lifetime is assigned to all elided output lifetimes.
  • If there are multiple input lifetime positions, but one of them is &self or &mut self, the lifetime of self is assigned to all elided output lifetimes.
  • Otherwise, it is an error to elide an output lifetime.


, , , , . . , -



struct Point(i32, i32);

impl Point {
    pub fn get_x(&self) -> &i32 {
        &self.0
    }

    pub fn get_y(&self) -> &i32 {
        &self.1
    }
}


, , .







, ( GC), ( ). : . , " ".





. , , :





. Rust 2018, . , . , .



pub struct Node {
    value: u64,
    next: Option<Box<Node>>,
    prev: Option<Box<Node>>,
}


, , .. Box<Node> , unique_ptr C++. , ,



:



pub struct Node {
    value: u64,
    next: Option<&Box<Node>>,
    prev: Option<&Box<Node>>,
}


( shared_ptr), . : - - . " , - ", dangling pointers . -, , , - " , , ".



, " ". , , , , ( Rc/Arc/Cell/RefCell), , .



: , . , , // . : GC , WeakReferences byte[] , , , . JS, , .



, " ", , . , , . , , . - , - . ownership'. , , , , .





. , , , .



,



error[E0382]: assign to part of moved value: `head`
  --> src\main.rs:23:5
   |
19 |         prev: Some(Box::new(head)),
   |                             ---- value moved here
...
23 |     head.next = Some(Box::new(next));
   |     ^^^^^^^^^ value partially assigned here after move
   |
   = note: move occurs because `head` has type `Node`, which does not implement the `Copy` trait


, , . , Copy , , - "", . , " ?".



, , compiler-driven development. , - , ", - . , . , ". , , :



fn foo<T: Copy>() {

}

fn bar<T>() {
    foo::<T>();
}


, :



error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
 --> src\main.rs:6:5
  |
6 |     foo::<T>();
  |     ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
  |
  = help: consider adding a `where T: std::marker::Copy` bound
note: required by `foo`
 --> src\main.rs:1:1
  |
1 | fn foo<T: Copy>() {
  | ^^^^^^^^^^^^^^^^^

error: aborting due to previous error


where T: std::marker::Copy , , , !



, IDE , - , , / , - , IDE. - , , CI - - - . - IDE , , , . .



- , . , . , , , . .



, , . , , . . FFI ++ , . , . C# , " null", " KeyNotFoundException", " ", .. JS ( ) , .



, == . , , , . , , buffer overflow . , ( ).





— , , . . -, , , , , , , . , , , , C#/Java/Go/… , . , — . , , — .



. , , , , , , ", , !". , , . , , ( Java/C#/..., ), ( /++), , .



, , , , . , " ". , , - .



')

Source: https://habr.com/ru/post/434200/



All Articles