0Pricing
Learn Rust Coding · Pelajaran

Mendefinisikan dan Menerapkan Trait

Kuasai trait untuk mendefinisikan perilaku bersama di berbagai tipe, serupa dengan interface dalam bahasa lain.

Mendefinisikan dan Menerapkan Trait adalah pelajaran Learn Rust Coding gratis di CoddyKit. Ini adalah pelajaran 2 dari 3. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Learn Rust Coding, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Learn Rust Coding mencakup 3 pelajaran total.

Apa Itu Trait dalam Rust?

Dalam Rust, trait adalah cara yang ampuh untuk mendefinisikan perilaku bersama di antara berbagai jenis. Anggaplah trait seperti antarmuka dalam bahasa lain.

Trait memberi tahu Rust bahwa suatu jenis memiliki fungsionalitas tertentu. Jika suatu jenis mengimplementasikan trait, berarti jenis tersebut menyediakan method yang didefinisikan oleh trait itu.

  • Trait memungkinkan polimorfisme: bekerja dengan berbagai jenis secara seragam.
  • Trait merupakan bagian penting dari sistem jenis dan abstraksi yang aman dalam Rust.

Mendeklarasikan Trait Pertama Anda

Anda mendefinisikan trait menggunakan kata kunci trait. Di dalamnya, Anda mencantumkan tanda tangan method (nama, parameter, dan jenis nilai yang dikembalikan) yang harus disediakan oleh setiap jenis yang mengimplementasikannya.

Mari kita definisikan trait Summary sederhana untuk item yang dapat diringkas.

trait Summary {
  fn summarize(&self) -> String;
}

fn main() {
  // Traits are definitions, not directly executable.
  // We will implement and use them in later scenes!
  println!("Trait 'Summary' defined.");
}

Mengimplementasikan Trait untuk Jenis

Untuk membuat suatu jenis menggunakan trait, Anda menggunakan sintaks impl Trait for Type. Selanjutnya, Anda menyediakan implementasi konkret untuk setiap method yang didefinisikan dalam trait tersebut.

Di sini, kita mengimplementasikan Summary untuk struct NewsArticle.

trait Summary {
  fn summarize(&self) -> String;
}

struct NewsArticle {
  headline: String,
  location: String,
  author: String,
  content: String,
}

impl Summary for NewsArticle {
  fn summarize(&self) -> String {
    format!("{}, by {} ({})", self.headline, self.author, self.location)
  }
}

fn main() {
  let article = NewsArticle {
    headline: String::from("Penguins win Stanley Cup!"),
    location: String::from("Pittsburgh, PA"),
    author: String::from("Iceburgh"),
    content: String::from("The Pittsburgh Penguins have won..."),
  };

  println!("New article summary: {}", article.summarize());
}

Menggunakan Fungsi dengan Batas Trait

Setelah suatu jenis mengimplementasikan trait, Anda dapat menulis fungsi yang menerima jenis apa pun yang mengimplementasikan trait tersebut. Dengan demikian, Anda dapat membuat kode yang fleksibel dan generik.

Fungsi notify dapat menerima jenis apa pun yang mengimplementasikan Summary.

trait Summary {
  fn summarize(&self) -> String;
}

struct NewsArticle {
  headline: String,
  location: String,
  author: String,
  content: String,
}

impl Summary for NewsArticle {
  fn summarize(&self) -> String {
    format!("{}, by {} ({})", self.headline, self.author, self.location)
  }
}

struct Tweet {
  username: String,
  content: String,
  reply: bool,
  retweet: bool,
}

impl Summary for Tweet {
  fn summarize(&self) -> String {
    format!("{}: {}", self.username, self.content)
  }
}

fn notify(item: &impl Summary) { // impl Summary is syntax sugar for a trait bound
  println!("Breaking news! {}", item.summarize());
}

fn main() {
  let tweet = Tweet {
    username: String::from("horse_ebooks"),
    content: String::from("of course, as you probably already know, people"),
    reply: false,
    retweet: false,
  };

  let article = NewsArticle {
    headline: String::from("Rust is awesome!"),
    location: String::from("Internet"),
    author: String::from("Rustacean"),
    content: String::from("Rust's type system is amazing."),
  };

  notify(&tweet);
  notify(&article);
}

Trait dengan Perilaku Bawaan

Trait juga dapat menyediakan implementasi bawaan untuk method-nya. Artinya, jenis tidak harus mengimplementasikan setiap method jika implementasi bawaan telah tersedia.

Jenis tersebut dapat memilih untuk menggunakan bawaan atau menggantinya dengan logikanya sendiri.

trait Summary {
  fn summarize_author(&self) -> String; // New required method
  fn summarize(&self) -> String { // Default implementation
    format!("(Read more from {})", self.summarize_author())
  }
}

struct Tweet {
  username: String,
  content: String,
  reply: bool,
  retweet: bool,
}

impl Summary for Tweet {
  fn summarize_author(&self) -> String { // Must implement required method
    format!("@{}", self.username)
  }
  // We are using the default summarize() method here!
}

fn main() {
  let tweet = Tweet {
    username: String::from("dog_lover"),
    content: String::from("My dog is the best!"),
    reply: false,
    retweet: false,
  };

  println!("Tweet summary: {}", tweet.summarize());
}

Fungsi Generik dengan Trait

Saat menulis fungsi atau struct generik, Anda dapat menggunakan batas trait untuk menentukan bahwa parameter jenis generik T harus mengimplementasikan trait tertentu.

Hal ini memastikan bahwa method dari trait tersebut tersedia untuk T.

trait Displayable {
  fn display(&self);
}

struct Point<T> {
  x: T,
  y: T,
}

// Implement Displayable for Point<i32>
impl Displayable for Point<i32> {
  fn display(&self) {
    println!("Point: ({}, {})", self.x, self.y);
  }
}

// Generic function that works for any type T that implements Displayable
fn print_item<T: Displayable>(item: T) {
  item.display();
}

fn main() {
  let p = Point { x: 10, y: 20 };
  print_item(p);
  // This function only works for types that implement Displayable
  // let s = String::from("Hello");
  // print_item(s); // This would cause a compile-time error
}

Menggabungkan Beberapa Batas Trait

Terkadang, suatu jenis generik perlu mengimplementasikan lebih dari satu trait. Anda dapat menentukan beberapa batas trait menggunakan operator +.

Untuk skenario yang lebih kompleks, terutama dengan banyak parameter generik, klausa where dapat meningkatkan keterbacaan.

use std::fmt::Debug;

trait Printable {
  fn print_info(&self);
}

struct Book {
  title: String,
  pages: u32,
}

impl Printable for Book {
  fn print_info(&self) {
    println!("Book: '{}' ({} pages)", self.title, self.pages);
  }
}

impl Debug for Book { // Book also implements Debug trait
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    write!(f, "Book {{ title: {}, pages: {} }}", self.title, self.pages)
  }
}

// A function that requires its argument to be both Printable and Debug
fn process_item<T: Printable + Debug>(item: T) {
  item.print_info();
  println!("Debug info: {:?}", item);
}

fn main() {
  let my_book = Book {
    title: String::from("The Rust Book"),
    pages: 600,
  };

  process_item(my_book);
}

Mengembalikan Jenis dengan `impl Trait`

Sintaks impl Trait tidak hanya digunakan untuk parameter fungsi; sintaks ini juga dapat digunakan pada posisi nilai kembalian. Ini berguna ketika Anda ingin mengembalikan tipe yang mengimplementasikan sifat tertentu, tetapi tidak ingin mengekspos tipe konkretnya.

Sintaks ini menyederhanakan tanda tangan fungsi dan membuat API Anda tetap fleksibel.

trait Greeter {
  fn greet(&self) -> String;
}

struct FriendlyGreeter;
impl Greeter for FriendlyGreeter {
  fn greet(&self) -> String {
    String::from("Hello there!")
  }
}

struct FormalGreeter;
impl Greeter for FormalGreeter {
  fn greet(&self) -> String {
    String::from("Greetings and salutations.")
  }
}

// This function returns *some* type that implements Greeter
// The caller doesn't need to know if it's FriendlyGreeter or FormalGreeter
fn get_greeter(formal: bool) -> impl Greeter {
  if formal {
    FormalGreeter
  } else {
    FriendlyGreeter
  }
}

fn main() {
  let casual_greet = get_greeter(false);
  println!("{}", casual_greet.greet());

  let formal_greet = get_greeter(true);
  println!("{}", formal_greet.greet());
}

Membangun Berdasarkan Sifat Induk

Terkadang, satu sifat secara logis bergantung pada sifat lainnya. Rust memungkinkan Anda mendefinisikan sifat induk, yang berarti suatu sifat dapat mensyaratkan bahwa setiap tipe yang mengimplementasikannya juga harus mengimplementasikan sifat spesifik lainnya.

Hal ini dilakukan dengan sintaks trait SubTrait: SuperTrait. Ibarat mengatakan, "jika Anda dapat melakukan X, Anda juga harus dapat melakukan Y".

trait Printable {
  fn print_content(&self);
}

// Debug is a supertrait of PrintableDebug
// Any type implementing PrintableDebug must also implement Debug
trait PrintableDebug: Printable + std::fmt::Debug {
  fn print_debug_and_content(&self) {
    self.print_content();
    println!("Debug info: {:?}", self);
  }
}

struct Item {
  id: u32,
  name: String,
}

impl Printable for Item {
  fn print_content(&self) {
    println!("Item ID: {}, Name: {}", self.id, self.name);
  }
}

impl std::fmt::Debug for Item {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    write!(f, "Item {{ id: {}, name: {} }}", self.id, self.name)
  }
}

// Now we can implement PrintableDebug because Item implements both Printable and Debug
impl PrintableDebug for Item {}

fn main() {
  let my_item = Item {
    id: 101,
    name: String::from("Widget A"),
  };
  my_item.print_debug_and_content();
}

Uji Pengetahuan Anda tentang Sifat

Perhatikan potongan kode Rust berikut. Manakah pernyataan berikut tentang sifat dan batas sifat yang TRUE?

Sifat: Perangkat Kerja untuk Perilaku

Kita telah mempelajari sistem sifat Rust yang sangat kuat!

  • Sifat mendefinisikan sekumpulan metode yang dapat diimplementasikan oleh suatu tipe, dan berfungsi seperti antarmuka.
  • Anda mengimplementasikan sifat untuk tipe tertentu menggunakan impl Trait for Type.
  • Batas sifat (T: Trait) memungkinkan fungsi dan struktur generik beroperasi pada tipe apa pun yang mengimplementasikan sifat yang diperlukan.
  • Sifat dapat memiliki implementasi bawaan, dan Anda dapat menentukan beberapa batas sifat (T: Trait1 + Trait2) atau menggunakan sifat induk.
  • impl Trait juga dapat digunakan pada posisi nilai kembalian untuk menyembunyikan tipe konkret.

Sifat merupakan dasar penting untuk menulis kode Rust yang fleksibel, dapat digunakan kembali, dan aman!

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Mendefinisikan dan Menerapkan Trait” gratis?

Ya — teks lengkap “Mendefinisikan dan Menerapkan Trait” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Learn Rust Coding, upgrade ke CoddyKit PRO. Kursus Learn Rust Coding mencakup 3 pelajaran total.

Apa yang akan aku pelajari di “Mendefinisikan dan Menerapkan Trait”?

Kuasai trait untuk mendefinisikan perilaku bersama di berbagai tipe, serupa dengan interface dalam bahasa lain. Kamu berlatih Learn Rust Coding dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai Learn Rust Coding?

Tidak diperlukan pengalaman sebelumnya. Learn Rust Coding di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 3.

Berapa lama pelajaran “Mendefinisikan dan Menerapkan Trait” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran Learn Rust Coding ini?

Ya. Setiap pelajaran Learn Rust Coding menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Menulis Kode Generik dalam Rust
  2. Mendefinisikan dan Menerapkan Trait
  3. Penggunaan Trait Tingkat Lanjut: Tipe Terkait
← Kembali ke Learn Rust Coding