Lär dig programmera i Rust · Lektion

Generiska funktioner

Parametrisera beteende efter typ.

Lektion 1 av 413 steg

Generiska funktioner är en gratis lektion i Lär dig programmera i Rust på CoddyKit. Detta är lektion 1 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Lär dig programmera i Rust, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Lär dig programmera i Rust innehåller totalt 4 lektioner.

Varför generiska funktioner

Med generiska funktioner kan ni skriva en funktion som fungerar med många typer i stället för att kopiera kod för varje typ. Rust ersätter platshållartypen vid kompilering.

Föreställ er att skriva en largest för heltal och en annan för tecken. Generics sammanför dem till en enda definition utan kostnad vid körning.

Typparametrar

En generisk funktion deklarerar en typparameter inom vinkelparenteser efter namnet. Namnet T är en konvention, men alla CamelCase-identifierare fungerar.

Parametern kan sedan förekomma i argumenten och returtypen och representerar den konkreta typ som anroparen använder.

fn first<T>(pair: (T, T)) -> T {
    pair.0
}

En enkel identitetsfunktion

Programmet definierar en generisk echo som returnerar sitt argument oförändrat. Den anropas en gång med ett heltal och en gång med en strängslice.

Kompilatorn genererar en separat konkret version för varje typ som faktiskt används.

fn echo<T>(value: T) -> T {
    value
}

fn main() {
    println!("{}", echo(42));
    println!("{}", echo("hi"));
}

Monomorfisering

Rust använder monomorfisering: vid kompilering skapas en specialiserad kopia av funktionen för varje konkret typ som används. Det förekommer ingen boxing eller virtuell dispatch.

Resultatet är generisk kod som körs lika snabbt som handskriven, typspecifik kod.

Generics behöver begränsningar

I en generisk funktion kan ni bara använda operationer som alla möjliga typer stöder. Ett naket T kan inte adderas, jämföras eller skrivas ut.

Den här koden kan inte kompileras eftersom T kanske inte implementerar jämförelse. Vi löser det härnäst med en trait-begränsning.

fn larger<T>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

Lägg till en trait-begränsning

För att jämföra värden begränsar vi T med PartialOrd. Begränsningen garanterar att typen stöder operatorn >.

Vi lägger också till Copy så att värdena kan returneras utan flyttproblem för enkla typer som heltal.

fn larger<T: PartialOrd + Copy>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

Anropa den begränsade funktionen

Nu fungerar funktionen för alla typer som implementerar båda traits. Både heltal och flyttal uppfyller PartialOrd + Copy.

Samma källkod, monomorfiserad till två versioner, skriver ut resultat för varje anrop.

fn larger<T: PartialOrd + Copy>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

fn main() {
    println!("{}", larger(3, 9));
    println!("{}", larger(2.5, 1.0));
}

Flera typparametrar

En funktion kan deklarera flera typparametrar. Varje parameter är oberoende, så de två argumenten kan ha olika typer.

Här tar pair emot valfritt T och valfritt U och returnerar dem som en tupel.

fn pair<T, U>(a: T, b: U) -> (T, U) {
    (a, b)
}

Skriva ut generiska värden

För att skriva ut ett generiskt värde med {} måste typen implementera Display. Vi lägger till den begränsningen så att alla utskrivbara typer kan skickas in.

Detta etiketterar ett värde och returnerar det, vilket visar en begränsning som används enbart för formatering.

use std::fmt::Display;

fn announce<T: Display>(label: &str, value: T) {
    println!("{}: {}", label, value);
}

fn main() {
    announce("count", 7);
    announce("name", "Ada");
}

Turbofish-syntax

Ibland kan kompilatorn inte härleda T enbart från argumenten. Med turbofish ::<Type> kan ni ange typen explicit vid anropsplatsen.

Det är vanligast med metoder som parse och collect, där returtypen är tvetydig.

fn main() {
    let n = "42".parse::<i32>().unwrap();
    println!("{}", n + 1);
}

Generics över referenser

Generiska parametrar fungerar även med referenser. Genom att begränsa via referens undviker ni att kräva Copy när ni bara behöver läsa värden.

Den här hjälpfunktionen av typen longest_str lånar två slicar och returnerar en av dem utan att ta över ägarskapet.

fn pick<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> &'a T {
    if a > b { a } else { b }
}

Snabb kontroll

Testa er förståelse av generiska funktioner i Rust.

Sammanfattning

Generiska funktioner använder typparametrar inom vinkelparenteser för att fungera med många typer utan kostnad vid körning genom monomorfisering.

Operationer på en generisk typ kräver trait-begränsningar som PartialOrd, Copy eller Display. Använd turbofish när typinferensen inte kan avgöra typen.

Gratis att börja

Lär dig Rust med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
39
Lektioner
144

Vanliga frågor

Är lektionen ”Generiska funktioner” gratis?

Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Lär dig programmera i Rust, inklusive ”Generiska funktioner”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Lär dig programmera i Rust innehåller totalt 4 lektioner.

Vad lär jag mig i ”Generiska funktioner”?

Parametrisera beteende efter typ. Ni övar på Lär dig programmera i Rust med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig Lär dig programmera i Rust?

Du behöver inga förkunskaper. Utbildningen i Lär dig programmera i Rust på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 1 av 4.

Hur lång tid tar lektionen ”Generiska funktioner”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här Lär dig programmera i Rust-lektionen?

Ja. Varje Lär dig programmera i Rust-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Generiska funktioner
  2. Generiska structs och enum-typer
  3. Trait-begränsningar
  4. where-satser och flera begränsningar
← Tillbaka till Lär dig programmera i Rust