# Rust syntax jämfört med C++

14 augusti 2026 | https://www.ribomation.se/blog/2026/rust-syntax-jamfort-med-c++/

Föregående artikel handlade om buggar Rust-kompilatorn stoppar. Den här handlar om något mer grundläggande: hur koden ser ut innan man ens hunnit skriva en bugg. Två språk som båda kompilerar till maskinkod och båda kallar sig systemspråk kan se förvånansvärt olika ut rad för rad — och skillnaderna är sällan godtyckliga. De flesta går att spåra till ett designbeslut om vad som ska vara standard och vad som ska krävas explicit.

Jag går igenom åtta sådana skillnader, grupperade i tre delar:

**Defaults som skiljer sig**

1.  Immutable vs. mutable
2.  Move-semantics vs. copy-semantics

**Blockens och satsernas form**

3.  Parenteser som försvinner, klamrar som blir obligatoriska
4.  Ingen C-loop kvar
5.  Blocket som är ett uttryck
6.  Pilen är obligatorisk, inte kosmetisk

**Deklarationer och typer**

7.  Bitbredden står i typnamnet
8.  Ingen overloading, inga default-argument

* * *

1\. Muterbar som standard — eller inte
--------------------------------------

Börjar vi med den mest grundläggande skillnaden av alla, för den sätter tonen för resten av artikeln. I C++ är en variabel muterbar (_mutable_) om du inte säger något annat. I Rust är den oföränderlig (_immutable_) om du inte säger något annat. Samma rad kod, `total = 1200`, betyder alltså två olika löften beroende på språk.

```cpp
int total = 1200;                        // the list price, or so the name suggests

total = apply_discount(total, 20);        // "just applying the campaign discount"
total = apply_discount(total, 10);        // ...six months later, loyalty stacks on top
```

```console
$ g++ -std=c++23 -Wall -Wextra mutability.cxx -o mutability-c++ && ./mutability-c++
list price:     1200
after campaign:  960
after loyalty:   864
```

Inget av detta är fel — `total` ska uppenbarligen räknas om. Men språket gör ingen skillnad mellan en variabel du avsett ska ändras och en du råkat skriva till en gång för mycket. Verktyget för att uttrycka avsikten finns, `const`, men det är opt-in, en extra sak att komma ihåg per variabel: (`const int total = 1200;`)

```console
$ g++ -std=c++23 -Wall -Wextra mutability-const.cxx -o mutability-const-c++
mutability-const.cxx:12:11: error: assignment of read-only variable ‘total’
```

Samma program i Rust, fast utan `mut`:

```rust
let total = 1200;

total = apply_discount(total, 20);
total = apply_discount(total, 10);
```

```console
$ rustc --edition 2024 mutability.rs -o mutability-rust
error[E0384]: cannot assign twice to immutable variable `total`
  --> mutability.rs:10:5
   |
 6 |     let total = 1200;
   |         ----- first assignment to `total`
...
10 |     total = apply_discount(total, 20);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
   |
help: consider making this binding mutable
   |
 6 |     let mut total = 1200;
   |         +++
```

Ingen `const` att komma ihåg — `let` **är** `const` tills du säger något annat. Vill du faktiskt att `total` ska räknas om, vilket är fallet här, skriver du `let mut total` och menar det: (`let mut total = 1200;`)

```console
$ rustc --edition 2024 mutability-fixed.rs -o mutability-fixed-rust && ./mutability-fixed-rust
list price:     1200
after campaign:  960
after loyalty:   864
```

Samma utskrift som C++-versionen. Skillnaden är inte vad programmet gör, utan att en läsare som bara ser deklarationsraden redan vet om variabeln kommer att ändras längre ner — utan att behöva läsa resten av funktionen för att kolla.

2\. Kopiera som standard — eller flytta
---------------------------------------

Samma rad, `auto b = a;` respektive `let b = a;`, betyder olika saker i de två språken. Föregående artikels första avsnitt visade vad som händer när den skillnaden biter en i efterhand; här handlar det bara om själva defaulten.

```cpp
std::vector<int> a = {1, 2, 3, 4, 5};
auto b = a;                     // copies the whole vector

b.push_back(6);
```

```console
$ g++ -std=c++23 -Wall -Wextra assignment.cxx -o assignment-c++ && ./assignment-c++
a has 5 elements
b has 6 elements
```

`b` blir en egen kopia. Att lägga till ett element i `b` påverkar inte `a`, vilket är precis vad man väntar sig — men det innebär också att hela vektorn kopierades i tysthet, oavsett om avsikten var det eller inte.

```rust
let a = vec![1, 2, 3, 4, 5];
let mut b = a;                  // moves ownership of the vector, does not copy it

b.push(6);
```

```console
$ rustc --edition 2024 assignment.rs -o assignment-rust
error[E0382]: borrow of moved value: `a`
 --> assignment.rs:7:35
  |
2 |     let a = vec![1, 2, 3, 4, 5];
  |         - move occurs because `a` has type `Vec`, which does not implement the `Copy` trait
3 |     let mut b = a;                  // moves ownership of the vector, does not copy it
  |                 - value moved here
...
7 |     println!("a has {} elements", a.len());
  |                                   ^ value borrowed here after move
  |
help: consider cloning the value if the performance cost is acceptable
  |
3 |     let mut b = a.clone();                  // moves ownership of the vector, does not copy it
  |                  ++++++++
```

`let b = a;` flyttar äganderätten, den kopierar inte. Efter den raden finns det ingen `a` kvar att läsa, och kompilatorn säger det innan något ens körts.

Kompilatorns eget förslag pekar rakt på lösningen — `.clone()`:

```console
$ rustc --edition 2024 assignment-clone-fixed.rs -o assignment-fixed-rust && ./assignment-fixed-rust
a has 5 elements
b has 6 elements
```

Samma utskrift som C++, och nu ser man den omvända bilden av avsnitt 1. I C++ ber du om att **slippa** en kopiering, med `std::move`. I Rust ber du om att **få** en, med `.clone()`. Vilket som är standard är den egentliga skillnaden — inte att någotdera alternativet skulle saknas.

```cpp
std::vector<int> a = {1, 2, 3, 4, 5};
auto b = std::move(a);                     // moves the content of the vector
b.push_back(6);
```

3\. Parenteser som försvinner, klamrar som blir obligatoriska
-------------------------------------------------------------

C++ kräver parenteser runt villkoret i `if`/`while` men gör klamrarna runt kroppen valfria — en enda sats behöver inga. Rust gör precis tvärtom: inga parenteser, men klamrarna är obligatoriska. Det här avsnittet handlar om vad den bytesaffären köper dig.

```cpp
void log_access(bool is_admin) {
    if (is_admin)
        std::cout << "admin check passed\n";
        std::cout << "access granted\n";   // indentation lies: this always runs
}
```

```console
$ g++ -std=c++23 -Wall -Wextra access.cxx -o access-c++ && ./access-c++
access.cxx: In function ‘void log_access(bool)’:
access.cxx:4:5: warning: this ‘if’ clause does not guard... [-Wmisleading-indentation]
    4 |     if (is_admin)
      |     ^~
access.cxx:6:9: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the ‘if’
    6 |         std::cout << "access granted\n";   // indentation lies: this always runs
      |         ^~~
-- as admin --
admin check passed
access granted
-- as guest --
access granted
```

`access granted` skrivs ut även för gästen — raden låg aldrig inne i `if`:et, trots indenteringen. Till g++:s heder: `-Wmisleading-indentation` (del av `-Wall` sedan GCC 6) fångar faktiskt den här. Men det är en varning, inte ett fel, så programmet kompilerar och kör med buggen kvar ändå.

Det finns ingen C++-formad variant av det här programmet att ens försöka i Rust — att utelämna klamrarna är ett parsningsfel, inte en stilfråga:

```rust
fn log_access(is_admin: bool) {
    if is_admin
        println!("admin check passed");
}
```

```console
$ rustc --edition 2024 access.rs -o access-rust
error: expected `{`, found `println`
 --> access.rs:3:9
  |
3 |         println!("admin check passed");
  |         ^^^^^^^ expected `{`
  |
note: the `if` expression is missing a block after this condition
 --> access.rs:2:8
  |
2 |     if is_admin
  |        ^^^^^^^^
help: you might have meant to write this as part of a block
```

Med klamrarna utskrivna, precis som Rust kräver:

```rust
fn log_access(is_admin: bool) {
    if is_admin {
        println!("admin check passed");
    }
    println!("access granted");
}
```

Så går kompileringen genom

```console
$ rustc --edition 2024 access-fixed.rs -o access-fixed-rust && ./access-fixed-rust
-- as admin --
admin check passed
access granted
-- as guest --
access granted
```

Samma beteende som C++-versionen — att `access granted` skrivs ut ovillkorligen var aldrig själva buggen. Men eftersom scopet måste stavas ut i klamrar istället för att läsas ur indenteringen finns det inget kvar för en `-Wmisleading-indentation`\-liknande varning att hitta: koden och indenteringen kan inte säga emot varandra.

4\. Ingen C-loop kvar
---------------------

Rust saknar den klassiska tredelade `for (init; villkor; steg)` helt — det finns bara `for pattern in iterator`, `while` och `loop`. Så här ser det ut om man av vana sträcker sig efter C++-formen, och vad den idiomatiska ersättningen blir istället.

```cpp
int sum = 0;
for (int i = 0; i < 10; i += 2) {
    sum += i;
}
```

```console
$ g++ -std=c++23 -Wall -Wextra stepping.cxx -o stepping-c++ && ./stepping-c++
sum = 20
```

Samma sak, försökt skrivet i Rust:

```rust
let mut sum = 0;
for (let mut i = 0; i < 10; i += 2) {
    sum += i;
}
```

```console
$ rustc --edition 2024 stepping.rs -o stepping-rust
error: expected pattern, found `let`
 --> stepping.rs:3:10
  |
3 |     for (let mut i = 0; i < 10; i += 2) {
  |          ^^^
  |
help: remove the unnecessary `let` keyword
  |
3 -     for (let mut i = 0; i < 10; i += 2) {
3 +     for (mut i = 0; i < 10; i += 2) {
  |

error: expected one of `)`, `,`, `@`, `if`, or `|`, found `=`
 --> stepping.rs:3:20
  |
3 |     for (let mut i = 0; i < 10; i += 2) {
  |                    ^ expected one of `)`, `,`, `@`, `if`, or `|`
```

Parsern försöker läsa `for (...)` som ett **mönster** att packa upp, för det är det enda som får stå mellan `for` och `in`. Det finns ingen tredelad header att tolka in i — den har aldrig funnits i grammatiken.

```rust
let mut sum = 0;
for i in (0..10).step_by(2) {
    sum += i;
}
```

```console
$ rustc --edition 2024 stepping-fixed.rs -o stepping-fixed-rust && ./stepping-fixed-rust
sum = 20
```

`(0..10).step_by(2)` ersätter init/villkor/steg med ett intervall och en adapter. Ingen räknare att deklarera för hand, inget off-by-one att göra fel på vid gränsen — och inget att glömma initiera, vilket för oss tillbaka till avsnitt 1.

5\. Blocket som är ett uttryck
------------------------------

I Rust kan `if`/`else` (och vilket `{ }`\-block som helst) vara ett värde — sista uttrycket i blocket, utan semikolon på slutet, är det som blocket blir. I C++ är `if`/`else` en sats; den kan inte lämna tillbaka något värde, så man tar antingen till villkorsoperatorn eller deklarerar en muterbar variabel i förväg och tilldelar den i varje gren.

```cpp
auto classify(int celsius) -> std::string {
    std::string label;               // has to exist before we know the answer
    if (celsius < 0) {
        label = "freezing";
    } else if (celsius < 15) {
        label = "cold";
    } else if (celsius < 25) {
        label = "mild";
    } else {
        label = "hot";
    }
    return label;
}
```

```console
$ g++ -std=c++23 -Wall -Wextra classify.cxx -o classify-c++ && ./classify-c++
-5 C -> freezing
10 C -> cold
20 C -> mild
30 C -> hot
```

Fyra grenar är en för många för en läsbar kedja av villkorsoperatorer, så `label` måste finnas innan någon gren körts, tilldelas i var och en, och returneras efteråt. Tre separata saker att få rätt — och avsnitt 1 visade redan vart "finns innan vi vet svaret" kan leda.

```rust
let label = if celsius < 0 {
    "freezing";                  // stray semicolon: this arm now yields ()
} else if celsius < 15 {
    "cold"
} else if celsius < 25 {
    "mild"
} else {
    "hot"
};
```

```console
$ rustc --edition 2024 classify.rs -o classify-rust
error[E0308]: `if` and `else` have incompatible types
  --> classify.rs:4:12
   |
 2 |       let label = if celsius < 0 {
   |                   -------------- `if` and `else` have incompatible types
 3 |           "freezing";                  // stray semicolon: this arm now yields ()
   |           -----------
   |           |         |
   |           |         help: consider removing this semicolon
   |           expected because of this
 4 |       } else if celsius < 15 {
   |  ____________^
 5 | |         "cold"
 6 | |     } else if celsius < 25 {
 7 | |         "mild"
 8 | |     } else {
 9 | |         "hot"
10 | |     };
   | |_____^ expected `()`, found `&str`
```

Ett enda extra `;` efter `"freezing"` gör att den grenens värde blir `()` — enhetstypen, Rusts "ingenting", inte C++:s `void`, och den deltar i typkontrollen precis som vilken annan typ som helst — istället för `&str`. De andra tre grenarna ger fortfarande `&str`, så grenarna är oense och hela `if`\-uttrycket faller på typkontrollen. Semikolonet är alltså inte kosmetiskt här; det är skillnaden mellan ett uttryck och en sats.

Så här ser det fungerande programmet ut i Rust:

```rust
fn classify(celsius: i32) -> &'static str {
    if celsius < 0 { "freezing" } 
    else if celsius < 15 { "cold" } 
    else if celsius < 25 { "mild" } 
    else { "hot" }
}

fn main() {
    for t in [-5, 10, 20, 30] {
        println!("{t} C -> {}", classify(t));
    }
}
```

```console
$ rustc --edition 2024 classify-fixed.rs -o classify-fixed-rust && ./classify-fixed-rust
-5 C -> freezing
10 C -> cold
20 C -> mild
30 C -> hot
```

Inga semikolon på grenarnas värden, och ingen `label`\-variabel alls — kedjan av `if`/`else if`/`else` är sista uttrycket i funktionskroppen, så den **är** returvärdet. Inget förhandsdeklarerat, inget omtilldelat, inget att lämna oinitierat på en gren någon glömmer.

6\. Pilen är obligatorisk, inte kosmetisk
-----------------------------------------

C++ har tre likvärdiga sätt att skriva samma funktion: den traditionella returtypen först, pil-formen `-> T` (C++11), och — sedan C++14 — ingen utskriven returtyp alls, härledd ur kroppen. Rust har bara ett sätt: `-> T` finns och stämmer, eller så returnerar funktionen `()` och inget typkontrolleras.

```cpp
int add_traditional(int a, int b) {
    return a + b;
}

auto add_trailing(int a, int b) -> int {
    return a + b;
}

auto add_inferred(int a, int b) {   // C++14: return type deduced, no arrow needed
    return a + b;
}
```

```console
$ g++ -std=c++23 -Wall -Wextra add.cxx -o add-c++ && ./add-c++
5
5
5
```

Alla tre gör samma sak och kompilerar likadant. Pilen i `auto add_trailing(int a, int b) -> int` är ett stilval — `add_inferred` bevisar att man inte ens behöver skriva ut någon returtyp, C++ räknar ut den från `return a + b;`.

```rust
fn add(a: i32, b: i32) {    // no "-> i32": does this get inferred, like C++'s auto?
    a + b
}
```

```console
$ rustc --edition 2024 add.rs -o add-rust
error[E0308]: mismatched types
 --> add.rs:2:5
  |
1 | fn add(a: i32, b: i32) {    // no "-> i32": does this get inferred, like C++'s auto?
  |                       - help: try adding a return type: `-> i32`
2 |     a + b
  |     ^^^^^ expected `()`, found `i32`

error[E0277]: `()` doesn't implement `std::fmt::Display`
 --> add.rs:6:20
  |
6 |     println!("{}", add(2, 3));
  |               --   ^^^^^^^^^ `()` cannot be formatted with the default formatter
```

Att utelämna `-> i32` utlöser inte samma sorts inferens som C++14:s `auto`. En `fn` utan pil **betyder** att den returnerar `()`, punkt slut — kroppens sista uttryck `a + b` blir då ett typfel, eftersom det är en `i32` som hamnar där `()` förväntades.

```console
$ rustc --edition 2024 add-fixed.rs -o add-fixed-rust && ./add-fixed-rust
5
```

Det finns inga andra sätt att skriva den här funktionen på. Varje `fn` som returnerar ett värde stavar ut `-> T`, så signaturen ensam berättar alltid svaret — man behöver aldrig läsa in i kroppen (eller lita på att en kommentar stämmer) för att ta reda på vad en funktion returnerar.

7\. Bitbredden står i typnamnet
-------------------------------

C++:s heltalsnamn (`int`, `char`, `size_t`) säger inget om maskinstorleken (bytes och-eller bits) för respektive type — det överlåts åt plattformen, och språket konverterar mellan dem utan att bli tillfrågat. Rusts typnamn (`i32`, `u8`, `usize`) anger maskinstorleken utan krusiduller, och det finns ingen implicit konvertering mellan två heltalstyper, någonsin.

```cpp
int big = 1000;
unsigned char narrowed = big;     // implicit narrowing, no cast asked for
```

```console
$ g++ -std=c++23 -Wall -Wextra narrow.cxx -o narrow-c++ && ./narrow-c++
big      = 1000
narrowed = 232
```

`unsigned char narrowed = big;` kompilerar **helt utan diagnostik** under `-Wall -Wextra` — det krävs `-Wconversion` specifikt för att bli varnad. `1000` ryms inte i 8 bitar, så det wrappar (modulo-aritmetik): `1000 % 256 = 232`.

```rust
let big: i32 = 1000;
let narrowed: u8 = big;           // no implicit conversion between integer types, ever
```

```console
$ rustc --edition 2024 narrow.rs -o narrow-rust
error[E0308]: mismatched types
 --> narrow.rs:3:24
  |
3 |     let narrowed: u8 = big;           // no implicit conversion between integer types, ever
  |                   --   ^^^ expected `u8`, found `i32`
  |                   |
  |                   expected due to this
  |
help: you can convert an `i32` to a `u8` and panic if the converted value doesn't fit
  |
3 |     let narrowed: u8 = big.try_into().unwrap();           // ...
```

`i32` och `u8` är olika typer, punkt slut — det spelar ingen roll att just den här konverteringen råkar vara krympande; Rust avvisar **all** implicit heltalskonvertering, även breddande sådan. Lägg märke till vad rustc föreslår: `try_into().unwrap()`, som panikar istället för att tyst wrappa om värdet inte ryms. Det är det "säkra" alternativet — och medvetet inte det den fixade versionen nedan använder.

```console
$ rustc --edition 2024 narrow-fixed.rs -o narrow-fixed-rust && ./narrow-fixed-rust
big      = 1000
narrowed = 232
```

`as u8` är den explicita, krympande casten — samma wraparound-aritmetik som C++-versionen, samma `232`. Utskriften är identisk med C++-programmet; skillnaden är att `as` fick skrivas ut för hand, exakt på det stället där krympningen sker, istället för att ske implicit varhelst en bredare typ möter en smalare.

Och för att visa att "säkert" ska tas bokstavligt: samma `big`, samma `try_into()` som rustc föreslog ovan — men den panikar, den wrappar inte:

```rust
let big: i32 = 1000;
let narrowed: u8 = big.try_into().unwrap();
```

```console
$ rustc --edition 2024 narrow-panic.rs -o narrow-panic-rust && ./narrow-panic-rust
thread 'main' (353814) panicked at narrow-panic.rs:3:39:
called `Result::unwrap()` on an `Err` value: TryFromIntError(PosOverflow)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```

Samma indata som fick `as u8` att tyst bli `232` får `try_into().unwrap()` att krascha programmet. Ingen av dem är "rätt" i något absolut mening — `as` är rätt när wrappningen är avsedd (kryptografi, hashning, bitmanipulation), `try_into()` är rätt när ett värde utanför intervallet är ett programmeringsfel som ska stoppa exekveringen direkt istället för att tyst ge fel svar.

8\. Ingen overloading, inga default-argument
--------------------------------------------

C++ löser `greet(name)` och `greet(name, greeting)` som två olika funktioner beroende på anropsstället. Rust har ingen overloading och inga default-värden på parametrar — ett namn betyder en signatur.

```cpp
void greet(const std::string& name) {
    std::cout << "Hello, " << name << "!\n";
}

void greet(const std::string& name, const std::string& greeting) {
    std::cout << greeting << ", " << name << "!\n";
}
```

```console
$ g++ -std=c++23 -Wall -Wextra greet.cxx -o greet-c++ && ./greet-c++
Hello, Ada!
Hej, Ada!
```

Två funktioner som heter `greet`, upplösta efter antal argument vid varje anropsställe. Inget ovanligt med det i C++ — rutin.

```rust
fn greet(name: &str) {
    println!("Hello, {name}!");
}

fn greet(name: &str, greeting: &str) {
    println!("{greeting}, {name}!");
}
```

```console
$ rustc --edition 2024 greet.rs -o greet-rust
error[E0428]: the name `greet` is defined multiple times
 --> greet.rs:5:1
  |
1 | fn greet(name: &str) {
  | -------------------- previous definition of the value `greet` here
...
5 | fn greet(name: &str, greeting: &str) {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `greet` redefined here
  |
  = note: `greet` must be defined only once in the value namespace of this module

error[E0061]: this function takes 1 argument but 2 arguments were supplied
  --> greet.rs:11:5
   |
11 |     greet("Ada", "Hej");
   |     ^^^^^        ----- unexpected argument #2 of type `&'static str`
```

Två `fn` med samma namn är ett hårt fel, inte overload-upplösning — `greet` upptar en enda plats i modulens namnrymd oavsett parameterlista. Det andra felet är en följdeffekt: med bara enparametersvarianten kvar matchar inte längre anropet med två argument något alls.

```console
$ rustc --edition 2024 greet-fixed.rs -o greet-fixed-rust && ./greet-fixed-rust
Hello, Ada!
Hej, Ada!
```

Två separata namn, `greet` och `greet_with`, där `greet` implementeras i termer av `greet_with`. Samma utskrift som C++-versionen. Anropsstället måste nu säga vilken av dem det menar — det finns ingen aritetsbaserad dispatch att luta sig mot, så de två beteendena får två namn istället för att dela på ett.

```rust
fn greet(name: &str) {
    greet_with("Hello", name);
}

fn greet_with(greeting: &str, name: &str) {
    println!("{greeting}, {name}!");
}

fn main() {
    greet("Ada");
    greet_with("Hej", "Ada");
}
```

* * *

Och vad blir kvar av det?
-------------------------

Åtta punkter, men egentligen bara en handfull grundfrågor som upprepas i olika skepnad: vad är standard och vad måste man be om, och vad räknas som ett värde och vad räknas bara som en instruktion. Muterbarhet (1), kopiering (2) och heltalskonvertering (7) är samma fråga — "vad händer om jag inte säger något" — ställd om variabler, äganderätt respektive typer. Parenteser (3), C-loopen (4) och uttrycksblock (5) är en annan variant av samma sak: hur mycket av satsens form är förhandlingsbar och hur mycket är fast. Pilen (6) och overloading (8) handlar båda om att en signatur ska gå att lita på utan att läsa kroppen.

Inget av det här är buggar i den mening föregående artikel handlade om — all exempelkoden i C++-spalten är fullt korrekt, avsiktligt skriven kod. Skillnaden är att C++ oftast ger dig ett val och en rimlig default, medan Rust oftare bara ger dig ett sätt. Det är bekvämt fram tills dagen du vill ha det andra sättet, och det är precis den avvägningen språkdesigners gör hela tiden — bara åt olika håll.

Om något av det här kändes som en detalj: det är poängen. Ingen enskild punkt är avgörande på egen hand. Tillsammans är de anledningen till att portering av kod, eller att bara växla mellan språken samma dag, ger den där låga bakgrundsfriktionen — fingrarna vet ett mönster, kompilatorn vill ha ett annat.

* * *

Saker jag hoppat över i denna artikel
-------------------------------------

Du har säkert noterat att det finns en del överhoppade begrepp i texten, såsom _panic_, `.unwrap()`, `&str` med flera. Under hösten kommer jag att beskriva dessa och flera andra i kommande artiklar.

* * *

Hur pass intresserad av Rust är du? Svara på en kort enkät!
-----------------------------------------------------------

var d=document,w="https://tally.so/widgets/embed.js",v=function(){"undefined"!=typeof Tally?Tally.loadEmbeds():d.querySelectorAll("iframe\[data-tally-src\]:not(\[src\])").forEach((function(e){e.src=e.dataset.tallySrc}))};if("undefined"!=typeof Tally)v();else if(d.querySelector('script\[src="'+w+'"\]')==null){var s=d.createElement("script");s.src=w,s.onload=v,s.onerror=v,d.body.appendChild(s);}
