Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Semantyka przenoszenia

An assignment will transfer ownership between variables:

fn main() {
    let s1: String = String::from("Hello!");
    let s2: String = s1;
    println!("s2: {s2}");
    // println!("s1: {s1}");
}
  • Przypisanie s1 do s2 przenosi własność.
  • When s1 goes out of scope, nothing happens: it does not own anything.
  • Kiedy zmienna s2 wychodzi poza zakres, dane łańcucha znaków są zwalniane.

Przed przeniesieniem do s2:

StackHeaps1ptrRustlen4capacity4

Po przeniesieniu do s2:

StosStertas1ptrRustlen4capacity4s2ptrlen4capacity4(inaccessible)

Kiedy przekazujesz wartość do funkcji, wartość jest przypisywana do parametru funkcji. To przenosi własność:

fn say_hello(name: String) {
    println!("Hello {name}")
}

fn main() {
    let name = String::from("Alice");
    say_hello(name);
    // say_hello(name);
}
This slide should take about 10 minutes.
  • Wspomnij, że jest to na odwrót niż w C++, który domyślnie kopiuje wartości chyba, że jest użyte std::move (i zdefiniowany konstruktor przenoszenia!).

  • It is only the ownership that moves. Whether any machine code is generated to manipulate the data itself is a matter of optimization, and such copies are aggressively optimized away.

  • Simple values (such as integers) can be marked Copy (see later slides).

  • W Ruście, klonowanie jest jawne (za pomocą clone).

In the say_hello example:

  • Przy pierwszym wywołaniu say_hello, main oddaje własność name. Potem name nie może być już użyte wewnątrz main.
  • Dane zaalokowane na stercie dla name będą zwolnione na końcu wywołania funkcji say_hello.
  • main może zachować własność jeżeli przekaże name jako referencję (&name) i jeżeli say_hello akceptuje referencję jako parameter.
  • Alternatywnie, main może przekazać klona name w pierwszym wywołaniu (name.clone()).
  • Przez używanie semantyki przenoszenia domyślnie i przez zmuszanie programistów do jawnego tworzenia klonów, Rust powoduje, że przypadkowe tworzenie kopii jest trudniejsze niż w C++.

More to Explore

Defensive Copies in Modern C++

Nowoczesny C++ rozwiązuje to inaczej:

std::string s1 = "Cpp";
std::string s2 = s1;  // Duplicate the data in s1.
  • Dane sterty z s1 są zduplikowane i s2 dostaje swoją niezależną kopię.
  • Kiedy s1 i s2 wychodzą poza zakres, obydwie zmienne zwalniają swoją pamięć.

Przed przypisywaniem kopiującym:

StackHeaps1ptrCpplen3capacity3

Po przypisaniu kopiującym:

StackHeaps1ptrCpplen3capacity3s2ptrCpplen3capacity3

Kluczowe punkty:

  • C++ has made a slightly different choice than Rust. Because = copies data, the string data has to be cloned. Otherwise we would get a double-free when either string goes out of scope.

  • C++ also has std::move, which is used to indicate when a value may be moved from. If the example had been s2 = std::move(s1), no heap allocation would take place. After the move, s1 would be in a valid but unspecified state. Unlike Rust, the programmer is allowed to keep using s1.

  • Unlike Rust, = in C++ can run arbitrary code as determined by the type which is being copied or moved.