10 nicht offensichtliche Vorteile der Verwendung von Rust

    Rust ist eine junge und ehrgeizige Systemprogrammiersprache. Es implementiert die automatische Speicherverwaltung ohne Garbage Collector und andere Ausführungszeiten. Darüber hinaus wird in der Sprache Rust die Semantik der Standardbewegung verwendet, es gibt beispiellose Regeln für den Zugriff auf die zu ändernden Daten, und die Lebensdauer der Links wird ebenfalls berücksichtigt. Dies ermöglicht es ihm, die Sicherheit des Speichers zu gewährleisten, und ermöglicht die Multithread-Programmierung aufgrund fehlender Datenrassen.



    All dies ist bereits allen bekannt, die die Entwicklung moderner Programmiertechnologien zumindest ein wenig beobachten. Was aber, wenn Sie kein Systemprogrammierer sind und in Ihren Projekten nicht viel Multithreading-Code vorhanden ist, die Leistung von Rust Sie dennoch reizt. Erhalten Sie zusätzliche Vorteile durch die Verwendung in angewandten Aufgaben? Oder alles, was er Ihnen zusätzlich geben wird, ist ein erbitterter Kampf mit dem Compiler, der Sie dazu zwingt, ein Programm zu schreiben, das konsequent den Regeln der Sprache für das Ausleihen und den Besitz folgt?


    Dieser Artikel enthält ein Dutzend nicht offensichtlicher und nicht besonders beworbener Vorteile der Verwendung von Rust, die Ihnen hoffentlich dabei helfen werden, sich für die Wahl dieser Sprache für Ihre Projekte zu entscheiden.


    1. Universalität der Sprache


    Trotz der Tatsache, dass Rust als Sprache für die Systemprogrammierung positioniert ist, eignet es sich auch für die Lösung hochrangiger Probleme. Sie müssen nicht mit rohen Zeigern arbeiten, wenn dies für Ihre Aufgabe nicht erforderlich ist. Die Standardsprachbibliothek hat bereits die meisten Typen und Funktionen implementiert, die für die Anwendungsentwicklung benötigt werden. Sie können auch externe Bibliotheken problemlos anschließen und verwenden. Das Typsystem und die allgemeine Programmierung in Rust ermöglichen die Verwendung von Abstraktionen auf einem ausreichend hohen Niveau, obwohl OOP in der Sprache nicht direkt unterstützt wird.


    Schauen wir uns einige einfache Beispiele für die Verwendung von Rust an.


    Ein Beispiel für die Kombination zweier Iteratoren zu einem Iterator über Elementpaare:


    let zipper: Vec<_> = (1..).zip("foo".chars()).collect();
    assert_eq!((1, 'f'), zipper[0]);
    assert_eq!((2, 'o'), zipper[1]);
    assert_eq!((3, 'o'), zipper[2]);

    Starten


    Hinweis: Ein Formataufruf name!(...)ist ein Funktionsmakroaufruf. Die Namen solcher Makros in Rust enden immer mit einem Symbol, !damit sie von den Namen der Funktionen und anderen Bezeichnern unterschieden werden können. Die Vorteile der Verwendung von Makros werden nachfolgend erläutert.

    Ein Beispiel für die Verwendung einer externen Bibliothek regexzum Arbeiten mit regulären Ausdrücken:


    externcrate regex;
    use regex::Regex;
    let re = Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
    assert!(re.is_match("2018-12-06"));

    Starten


    Ein Beispiel für die Typimplementierung Addfür eine benutzerdefinierte Struktur Pointzum Überladen des Additionsoperators:


    use std::ops::Add;
    structPoint {
        x: i32,
        y: i32,
    }
    impl Add for Point {
        typeOutput = Point;
        fnadd(self, other: Point) -> Point {
            Point { x: self.x + other.x, y: self.y + other.y }
        }
    }
    let p1 = Point { x: 1, y: 0 };
    let p2 = Point { x: 2, y: 3 };
    let p3 = p1 + p2;

    Starten


    Ein Beispiel für die Verwendung eines generischen Typs in einer Struktur:


    structPoint<T> {
        x: T,
        y: T,
    }
    let int_origin = Point { x: 0, y: 0 };
    let float_origin = Point { x: 0.0, y: 0.0 };

    Starten


    Auf Rust können Sie effektive Systemprogramme, große Desktopanwendungen, Mikrodienste, Webanwendungen (einschließlich des Client-Teils, da Rust in Wasm kompiliert werden kann) und mobile Anwendungen schreiben (obwohl das Ökosystem der Sprache in dieser Richtung nur schwach entwickelt ist). Diese Vielseitigkeit kann für mehrere Projektteams von Vorteil sein, da sie die Verwendung der gleichen Ansätze und der gleichen Module in vielen verschiedenen Projekten ermöglicht. Wenn Sie daran gewöhnt sind, dass jedes Werkzeug für seinen engen Umfang konzipiert ist, sollten Sie Rust als eine Box mit Werkzeugen mit derselben Zuverlässigkeit und Bequemlichkeit betrachten. Vielleicht fehlt dir das.


    2. Bequeme Build- und Abhängigkeitsverwaltungstools


    Dies wird eindeutig nicht angekündigt, aber viele bemerken, dass Rust eines der besten derzeit verfügbaren Build- und Abhängigkeitsverwaltungssysteme implementiert. Wenn Sie in C oder C ++ programmiert haben und die Verwendung der externen Bibliotheken schmerzlos für Sie akut war, wäre die Verwendung von Rust mit seinem Build-Tool und dem Cargo-Abhängigkeitsmanager eine gute Wahl für Ihre neuen Projekte.


    Neben der Tatsache, dass Cargo Abhängigkeiten für Sie herunterlädt und deren Versionen verwaltet, Anwendungen erstellt und ausführt, Tests ausführt und Dokumentation generiert, kann es außerdem mit Plugins für andere nützliche Funktionen erweitert werden. Beispielsweise gibt es Erweiterungen, mit denen Cargo veraltete Abhängigkeiten Ihres Projekts erkennen, eine statische Analyse des Quellcodes erstellen, Client-Teile von Webanwendungen erstellen und wiederherstellen und vieles mehr.


    Die Cargo-Konfigurationsdatei verwendet eine benutzerfreundliche und minimalistische Auszeichnungssprache, um die Projekteinstellungen zu beschreiben. Hier ist ein Beispiel einer typischen Konfigurationsdatei Cargo.toml:


    [package]
    name = "some_app"
    version = "0.1.0"
    authors = ["Your Name <you@example.com>"]
    [dependencies]
    regex = "1.0"
    chrono = "0.4"
    [dev-dependencies]
    rand = "*"

    Nachfolgend finden Sie drei typische Befehle für die Verwendung von Cargo:


    $ cargo check
    $ cargo test
    $ cargo run

    Sie werden verwendet, um den Quellcode auf Kompilierungsfehler zu prüfen, das Projekt zu erstellen und die Tests auszuführen bzw. das Programm zu erstellen und auszuführen.


    3. Eingebaute Tests


    Es ist so einfach und einfach, Komponententests in Rust zu schreiben, dass Sie es immer wieder tun möchten. :) Oft ist es einfacher für Sie, einen Komponententest zu schreiben, als die Funktionalität auf andere Weise zu testen. Hier ist ein Beispiel der Funktionen und Tests für sie:


    pubfnis_false(a: bool) -> bool {
        !a
    }
    pubfnadd_two(a: i32) -> i32 {
        a + 2
    }
    #[cfg(test)]mod test {
        use super::*;
        #[test]fnis_false_works() {
            assert!(is_false(false));
            assert!(!is_false(true));
        }
        #[test]fnadd_two_works() {
            assert_eq!(1, add_two(-1));
            assert_eq!(2, add_two(0));
            assert_eq!(4, add_two(2));
        }
    }

    Starten


    Funktionen in einem Modul, testdie mit einem Attribut gekennzeichnet #[test]sind, sind Komponententests. Sie werden beim Aufruf eines Befehls parallel ausgeführt cargo test. Das bedingte Kompilierungsattribut #[cfg(test)], das das gesamte Modul mit Tests kennzeichnet, führt dazu, dass das Modul nur bei der Ausführung der Tests kompiliert wird und nicht in die normale Baugruppe fällt.


    Es ist sehr praktisch, die Tests im selben Modul wie die getestete Funktionalität zu platzieren, indem einfach ein Submodul hinzugefügt wird test. Wenn Sie Integrationstests benötigen, platzieren Sie Ihre Tests einfach in einem Verzeichnis testsin der Projektwurzel und verwenden Sie Ihre Anwendung darin als externes Paket. In testdiesem Fall müssen keine separaten Anweisungen für das Modul und die bedingten Kompilierungen hinzugefügt werden.


    Beispiele für Dokumentation, die als Tests ausgeführt werden, verdienen besondere Aufmerksamkeit. Dies wird jedoch im Folgenden beschrieben.


    Es sind auch integrierte Leistungstests (Benchmarks) verfügbar, die jedoch noch nicht stabilisiert sind und daher nur in nächtlichen Compiler-Builds verfügbar sind. Bei stabilem Rust für diese Art von Tests müssen externe Bibliotheken verwendet werden.


    4. Gute Dokumentation mit aktuellen Beispielen.


    Die Standard-Rust-Bibliothek ist sehr gut dokumentiert. Die HTML-Dokumentation wird automatisch aus dem Quellcode mit Markdown-Beschreibungen in Dokumentkommentaren generiert. Darüber hinaus enthalten die Andockkommentare im Rust-Code Codebeispiele, die während des Testlaufs ausgeführt werden. Dies garantiert die Relevanz der Beispiele:


    /// Returns a byte slice of this `String`'s contents.////// The inverse of this method is [`from_utf8`].////// [`from_utf8`]: #method.from_utf8////// # Examples////// Basic usage:////// ```/// let s = String::from("hello");////// assert_eq!(&[104, 101, 108, 108, 111], s.as_bytes());/// ```#[inline]#[stable(feature = "rust1", since = "1.0.0")]pubfnas_bytes(&self) -> &[u8] {
        &self.vec
    }

    Dokumentation


    Hier ist ein Beispiel für die Verwendung des Verfahrens as_bytesin der ArtString


    let s = String::from("hello");
    assert_eq!(&[104, 101, 108, 108, 111], s.as_bytes());

    wird während des Testlaufs als Test ausgeführt.


    Für Rust-Bibliotheken ist es üblich, Beispiele für ihre Verwendung in Form kleiner unabhängiger Programme zu erstellen, die sich in einem Verzeichnis examplesin der Projektwurzel befinden. Diese Beispiele sind ebenfalls ein wichtiger Bestandteil der Dokumentation und werden auch während des Testlaufs zusammengestellt und ausgeführt. Sie können jedoch unabhängig von den Tests ausgeführt werden.


    5. Smart Type Autocast


    Im Rust-Programm können Sie den Typ des Ausdrucks nicht explizit angeben, wenn der Compiler ihn basierend auf dem Verwendungskontext automatisch ausgeben kann. Dies gilt nicht nur für die Orte, an denen Variablen deklariert werden. Schauen wir uns dieses Beispiel an:


    letmut vec = Vec::new();
    let text = "Message";
    vec.push(text);

    Starten


    Wenn wir die Typanmerkungen anordnen, sieht dieses Beispiel folgendermaßen aus:


    letmut vec: Vec<&str> = Vec::new();
    let text: &str = "Message";
    vec.push(text);

    Das heißt, wir haben einen Vektor von String-Slices und eine Variable vom Typ String-Slice. In diesem Fall ist es jedoch völlig unnötig, Typen anzugeben, da der Compiler sie selbst ableiten kann (unter Verwendung der erweiterten Version des Hindley-Milner- Algorithmus ). Die Tatsache, dass es sich vecum einen Vektor handelt, ist bereits für die Art des Rückgabewerts aus verständlich Vec::new(), aber es ist noch nicht klar, welche Art von Elementen es sein wird. Die Tatsache, dass ein Typ textein String-Slice ist, wird dadurch deutlich, dass ihm ein Literal dieses Typs zugewiesen wird. Somit wird der vec.push(text)Typ der Vektorelemente später deutlich . Beachten Sie, dass der gesamte Typ der Variablen vecdurch ihre Verwendung im Ausführungsthread und nicht während der Initialisierungsphase bestimmt wurde.


    Ein solches automatisches Ableitungssystem spart Code vor unnötigem Rauschen und macht es so kurz wie der Code in einer dynamisch typisierten Programmiersprache. Und dies unter Beibehaltung des strengen statischen Tippens!


    Natürlich können wir die Angabe von Typen in einer statisch typisierten Sprache nicht vollständig loswerden. Das Programm muss über Punkte verfügen, an denen garantiert gewährleistet ist, dass die Objekttypen bekannt sind, damit diese Typen an anderen Stellen angezeigt werden können. Solche Punkte in Rust sind Deklarationen von benutzerdefinierten Datentypen und Funktionssignaturen, in denen die verwendeten Typen nicht angegeben werden können. Sie können jedoch "metavariable Types" einführen, wenn Sie die generische Programmierung verwenden.


    6. Musterabgleich in Variablendeklarationsräumen.


    Bedienung let


    let p = Point::new();

    Tatsächlich ist es nicht auf die Deklaration neuer Variablen beschränkt. In Wirklichkeit wird der Ausdruck rechts vom Gleichheitszeichen mit dem Muster links abgeglichen. Und neue Variablen können in die Probe eingefügt werden (und nur auf diese Weise). Schauen Sie sich das folgende Beispiel an, und es wird Ihnen klarer:


    let Point { x, y } = Point::new();

    Starten


    Hier machte Destrukturierung: Eine solche Vergleichsgrößen einführen xund yzu initialisiert werden , um Felder den Wert xund yStruktur des Objekts , Pointdie durch den Aufruf zurückgegeben wird Point::new(). Die Zuordnung ist korrekt, da der Typ des Ausdrucks auf der rechten Seite Pointdem Typmuster Pointauf der linken Seite entspricht . In ähnlicher Weise können Sie beispielsweise die ersten beiden Elemente eines Arrays verwenden:


    let [a, b, _] = [1, 2, 3];

    Und noch viel mehr. Das Bemerkenswerteste an , dass solche Vergleiche sind in allen Orten gemacht , wo sie neue Variablennamen in Rust vorstellen können, nämlich die Betreiber match, let, if let, while let, in dem Kopfteilzyklus for, die Argumente von Funktionen und Verschlüssen. Hier ist ein Beispiel für die elegante Verwendung von Pattern Matching in einer Schleife for:


    for (i, ch) in"foo".chars().enumerate() {
        println!("Index: {}, char: {}", i, ch);
    }

    Starten


    Die enumeratevom Iterator aufgerufene Methode erstellt einen neuen Iterator, der nicht die Anfangswerte, sondern die Paare "Tupel", "Ordinalindex, Anfangswert" durchläuft. Während der Iterationen des Zyklus wird jedes dieser Tupel mit dem angegebenen Sample abgeglichen (i, ch), mit dem Ergebnis, dass die Variable iden ersten Wert vom Tupel erhält - den Index und die Variable ch- den zweiten, dh das Zeichenfolgezeichen. Im Rahmen der Schleife können wir diese Variablen weiter verwenden.


    Ein weiteres beliebtes Beispiel für die Verwendung eines Samples in einer Schleife for:


    for _ in0..5 {
        // Тело выполняется 5 раз
    }

    Hier ignorieren wir einfach den Iteratorwert anhand des Musters _. Weil die Iterationsnummer im Hauptteil der Schleife überhaupt nicht verwendet wird. Dasselbe kann zum Beispiel mit einem Funktionsargument gemacht werden:


    fnfoo(a: i32, _: bool) {
        // Второй аргумент никогда не используется
    }

    Oder beim Vergleich im Operator match:


    match p {
        Point { x: 1, .. } => println!("Point with x == 1 detected"),
        Point { y: 2, .. } => println!("Point with x != 1 and y == 2 detected"),
        _ => (), // Ничего не делаем во всех остальных случаях
    }

    Starten


    Durch das Abgleichen von Mustern wird der Code sehr kompakt und ausdrucksstark und ist für den Bediener in der matchRegel unverzichtbar. Der Operator matchist der Operator der vollständigen Variationsanalyse. Sie können also nicht versehentlich vergessen, einen der möglichen Übereinstimmungen für den analysierten Ausdruck zu überprüfen.


    7. Syntax-Erweiterung und Benutzer-DSL


    Die Syntax der Rust-Sprache ist begrenzt, hauptsächlich aufgrund der Komplexität des in der Sprache verwendeten Typsystems. In Rust gibt es beispielsweise keine benannten Argumente von Funktionen und Funktionen mit einer variablen Anzahl von Argumenten. Diese und andere Einschränkungen können Sie jedoch mit Makros umgehen. In Rust gibt es zwei Arten von Makros: deklarative und prozedurale. Mit deklarativen Makros werden Sie nie die gleichen Probleme haben wie Makros in C, weil sie hygienisch sind und nicht auf der Ebene der Textsubstitution arbeiten, sondern auf der Ebene der Substitution in einem abstrakten Syntaxbaum. Mithilfe von Makros können Sie Abstraktionen auf der Ebene der Syntax der Sprache erstellen. Zum Beispiel:


    println!("Hello, {name}! Do you know about {}?", 42, name = "User");

    Zusätzlich zu der Tatsache, dass dieses Makro die syntaktischen Funktionen zum Aufrufen der "Funktion" des Druckens einer formatierten Zeichenfolge erweitert, wird in seiner Implementierung auch geprüft, ob die Eingabeargumente zur Kompilierungszeit und nicht zur Laufzeit mit der angegebenen Formatzeichenfolge übereinstimmen. Mithilfe von Makros können Sie eine kurze Syntax für Ihre eigenen Designanforderungen eingeben, DSL erstellen und verwenden. Hier ein Beispiel für die Verwendung von JavaScript-Code in einem Rust-Programm, das in Wasm kompiliert wurde:


    let name = "Bob";
    let result = js! {
        var msg = "Hello from JS, " + @{name} + "!";
        console.log(msg);
        alert(msg);
        return2 + 2;
    };
    println!("2 + 2 = {:?}", result);

    Das Makro ist js!im Paket definiert stdwebund ermöglicht das Einbetten eines vollständigen JavaScript-Codes in Ihr Programm (mit Ausnahme von Strings in einfachen Anführungszeichen und Operatoren, die nicht durch ein Semikolon abgeschlossen sind) und die Verwendung von Objekten aus Rust-Code mithilfe von Syntax @{expr}.


    Makros bieten enorme Möglichkeiten, die Syntax von Rust-Programmen an die spezifischen Aufgaben eines bestimmten Fachgebiets anzupassen. Sie sparen Zeit und Aufmerksamkeit bei der Entwicklung komplexer Anwendungen. Nicht durch Erhöhung des Laufzeit-Overheads, sondern durch Erhöhung der Kompilierungszeit. :)


    8. Automatische Erzeugung des abhängigen Codes


    Prozedurale Ableitungsmakros in Rust werden häufig für die automatische Implementierung von Typen und andere Codegenerierung verwendet. Hier ist ein Beispiel:


    #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]structPoint {
        x: i32,
        y: i32,
    }

    Da all diese Zeichentypen ( Copy, Clone, Debug, Default, PartialEqund Eq) der Standardbibliothek für den Typen der Feldstruktur implementiert i32, dann im allgemeinen die gesamte Struktur ihrer Implementierung kann automatisch abgeleitet werden. Ein anderes Beispiel:


    externcrate serde_derive;
    externcrate serde_json;
    use serde_derive::{Serialize, Deserialize};
    #[derive(Serialize, Deserialize)]structPoint {
        x: i32,
        y: i32,
    }
    let point = Point { x: 1, y: 2 };
    // Сериализация Point в JSON строку.let serialized = serde_json::to_string(&point).unwrap();
    assert_eq!("{\"x\":1,\"y\":2}", serialized);
    // Десериализация JSON строки в Point.let deserialized: Point = serde_json::from_str(&serialized).unwrap();

    Starten


    Hier werden automatisch Ableitungsmakros Serializeund Methoden zur Serialisierung und Deserialisierung für die Struktur Deserializeaus der Bibliothek generiert. Anschließend können Sie eine Instanz dieser Struktur auf verschiedene Serialisierungsfunktionen übertragen, z. B. in einen JSON-String.serdePoint


    Sie können eigene prozedurale Makros erstellen, die den benötigten Code generieren. Oder verwenden Sie die vielen bereits erstellten Makros anderer Entwickler. Makros haben nicht nur den Programmierer vom Schreiben von Vorlagencode befreit, sondern haben auch den Vorteil, dass Sie nicht benötigen, dass verschiedene Teile des Codes konsistent gehalten werden. Wenn zum Beispiel Pointein drittes Feld zur Struktur hinzugefügt wird z, müssen Sie zur weiteren Sicherstellung der korrekten Serialisierung keine weiteren Schritte unternehmen. Wenn wir selbst die notwendigen Typen für die Serialisierung implementieren Point, müssen wir sicherstellen, dass diese Implementierung immer mit den neuesten Änderungen in der Struktur übereinstimmt Point.


    9. Algebraischer Datentyp


    Der algebraische Datentyp ist, vereinfacht gesagt, ein zusammengesetzter Datentyp, der eine Vereinigung von Strukturen darstellt. Formal ist dies eine Typensumme von Produkttypen. In Rust wird dieser Typ mit dem Schlüsselwort definiert enum:


    enumMessage {
        Quit,
        ChangeColor(i32, i32, i32),
        Move { x: i32, y: i32 },
        Write(String),
    }

    Der Typ eines bestimmten Werts einer Typvariablen Messagekann nur einer der in MessageStrukturtypen aufgeführten sein. Dies ist entweder eine einheitliche Struktur Quitohne Felder oder eine der Tupelstrukturen ChangeColoroder Writemit namenlosen Feldern oder eine reguläre Struktur Move. Ein herkömmlicher Aufzählungstyp kann als Sonderfall eines algebraischen Datentyps dargestellt werden:


    enumColor {
        Red,
        Green,
        Blue,
        White,
        Black,
        Unknown,
    }

    Mit Pattern Matching kann herausgefunden werden, welcher Typ in einem bestimmten Fall wirklich einen Wert angenommen hat:


    let color: Color = get_color();
    let text = match color {
        Color::Red => "Red",
        Color::Green => "Green",
        Color::Blue => "Blue",
        _ => "Other color",
    };
    println!("{}", text);
    ...
    fnprocess_message(msg: Message) {
        match msg {
            Message::Quit => quit(),
            Message::ChangeColor(r, g, b) => change_color(r, g, b),
            Message::Move { x, y } => move_cursor(x, y),
            Message::Write(s) => println!("{}", s),
        };
    }

    Starten


    In Form von algebraischen Datentypen implementiert Rust wichtige Arten wie Optionund Result, die verwendet werden , um den fehlenden Wert und das richtige / falsche Ergebnis darstellen. So wird es Optionin der Standardbibliothek definiert :


    pubenumOption<T> {
        None,
        Some(T),
    }

    In Rust gibt es keinen Nullwert, genau wie die ärgerlichen Fehler eines unerwarteten Zugriffs darauf. Wo es wirklich notwendig ist, die Möglichkeit des Fehlens eines Werts anzugeben, wird dieser verwendet Option:


    fndivide(numerator: f64, denominator: f64) -> Option<f64> {
        if denominator == 0.0 {
            None
        } else {
            Some(numerator / denominator)
        }
    }
    let result = divide(2.0, 3.0);
    match result {
        Some(x) => println!("Result: {}", x),
        None => println!("Cannot divide by 0"),
    }

    Starten


    Der algebraische Datentyp ist ein sehr mächtiges und ausdrucksstarkes Werkzeug, das die Tür für die typgetriebene Entwicklung öffnet. Ein kompetent geschriebenes Programm in diesem Paradigma zwingt dem Typensystem die meisten Überprüfungen auf die Richtigkeit seiner Arbeit. Wenn Ihnen Haskell in der täglichen Industrieprogrammierung fehlt, kann Rust Ihre Verkaufsstelle sein. :)


    10. Einfache Umgestaltung


    Das in Rust entwickelte strikte statische Typsystem und der Versuch, so viele Überprüfungen wie möglich während des Kompilierens durchzuführen, führen dazu, dass die Änderung und Umgestaltung des Codes sehr einfach und sicher wird. Wenn das Programm nach den Änderungen zusammengestellt wurde, sind nur noch logische Fehler vorhanden, die sich nicht auf die vom Compiler geprüfte Funktionalität beziehen. In Kombination mit der einfachen Möglichkeit, Unit-Tests zur Verifizierung der Logik hinzuzufügen, führt dies zu ernsthaften Garantien für die Programmzuverlässigkeit und zu einem erhöhten Vertrauen des Programmierers in die korrekte Ausführung seines Codes nach Änderungen.




    Vielleicht ist das alles, worüber ich in diesem Artikel sprechen wollte. Natürlich hat Rust viele andere Vorteile, und es gibt eine Reihe von Nachteilen (etwas Feuchtigkeit der Sprache, Fehlen der üblichen Programmiersprachen, "nicht-literarische" Syntax), die hier nicht erwähnt werden. Wenn Sie etwas zu erzählen haben, schreiben Sie in die Kommentare. Versuchen Sie im Allgemeinen Rust in der Praxis. Und vielleicht überwiegen seine Verdienste für Sie alle seine Mängel, wie es in meinem Fall der Fall war. Und schließlich bekommen Sie genau die Werkzeuge, die Sie schon lange gebraucht haben.

    Nur registrierte Benutzer können an der Umfrage teilnehmen. Bitte melden Sie sich an.

    Verwenden Sie Rust in Ihren Projekten?


    Jetzt auch beliebt: