서문 :이 답변은 이전에 기록 된 선택 하에서 내장 특성 -specifically 측면이 구현 -were. 이전 계획 (질문을 받았을 때 적용한 계획)에만 적용되는 섹션을 나타 내기 위해 블록 따옴표를 사용했습니다.Copy
기존 : 기본적인 질문에 답하기 위해 NoCopy
값을 저장하는 마커 필드를 추가 할 수 있습니다 . 예
struct Triplet {
one: int,
two: int,
three: int,
_marker: NoCopy
}
소멸자를 사용하여 ( Drop
trait 구현을 통해) 할 수도 있지만, 소멸자가 아무것도하지 않는 경우 마커 유형을 사용하는 것이 좋습니다.
이제 유형은 기본적으로 이동합니다. 즉, 새 유형을 정의 할 때 유형에 Copy
대해 명시 적으로 구현 하지 않는 한 구현 되지 않습니다 .
struct Triplet {
one: i32,
two: i32,
three: i32
}
impl Copy for Triplet {} // add this for copy, leave it out for move
구현은 모든 유형이 new struct
또는 enum
그 자체 인 경우에만 존재할 수 있습니다 Copy
. 그렇지 않은 경우 컴파일러는 오류 메시지를 인쇄합니다. 또한 유형 에 구현 이없는 경우에만 존재할 수 있습니다 Drop
.
당신이 묻지 않은 질문에 대답하기 위해 ... "무브와 카피는 어떻게 된거 야?":
먼저 두 가지 다른 "사본"을 정의하겠습니다.
- 바이트 사본 이있는 경우 만 얕게, 다음하지 포인터를 객체 바이트 별을 복사하는 예입니다,
(&usize, u64)
그것은 64 비트 컴퓨터에서 16 바이트이며, 얕은 복사는 그 16 바이트를 복용하고 자신을 복제 할 것 메모리의 다른 16 바이트 청크에서 값 없이 터치 usize
의 타단 &
. 즉,을 호출하는 것과 같습니다 memcpy
.
- 의미 사본 값을 복제는 안전하게 이전에 개별적으로 사용할 수있는 새 (다소) 독립적 인 인스턴스를 만들 수 있습니다. 예를 들어의 의미 론적 사본은
Rc<T>
참조 횟수를 늘리는 것과 관련되고,의 의미 론적 사본은 Vec<T>
새로운 할당을 생성 한 다음 각 저장된 요소를 이전 항목에서 새 항목 으로 의미 론적으로 복사하는 것을 포함합니다. 이러한 일 수 전체 복사본 (예 Vec<T>
) 또는 얕은 (예 Rc<T>
닿지 않도록 저장 T
), Clone
작업의 최소 량을 의미 타입의 값을 복사 할 필요 느슨하게 정의 T
내부 &T
로 T
.
Rust는 C와 같 으며 값의 모든 값 사용은 바이트 복사입니다.
let x: T = ...;
let y: T = x; // byte copy
fn foo(z: T) -> T {
return z // byte copy
}
foo(y) // byte copy
T
이동 여부에 관계없이 바이트 사본 이거나 "암시 적으로 복사 가능"합니다. (명확하게 말하면, 런타임에 문자 그대로 바이트 단위 사본 일 필요는 없습니다. 코드의 동작이 유지되는 경우 컴파일러는 사본을 자유롭게 최적화 할 수 있습니다.)
그러나 바이트 복사에는 근본적인 문제가 있습니다. 메모리에 중복 된 값이 생기며, 소멸자가 있으면 매우 나빠질 수 있습니다.
{
let v: Vec<u8> = vec![1, 2, 3];
let w: Vec<u8> = v;
} // destructors run here
만약이 w
단지 일반 바이트 사본이었다 v
일으키는 ... 다음 같은 할당 가리키는 두 벡터, 그것을 무료 소멸자 모두있을 것 더블 무료 문제이다를. NB. 이것은 우리가 v
into 의 의미 론적 복사본을한다면 완벽하게 괜찮을 것입니다 w
. 왜냐하면 그때 w
는 독립 Vec<u8>
적이고 파괴자가 서로를 짓밟 지 않을 것이기 때문입니다.
여기에 몇 가지 가능한 수정 사항이 있습니다.
- 프로그래머가 C처럼 처리하게하십시오. (C에는 소멸자가 없으므로 그렇게 나쁘지는 않습니다 ... 대신 메모리 누수가 남게됩니다. : P)
- 의미 복사를 암시 적으로 수행하여
w
복사 생성자가있는 C ++처럼 자체 할당을 갖도록합니다 .
- 가치 별 사용을 소유권 이전으로 간주하여
v
더 이상 사용할 수 없으며 소멸자가 실행되지 않습니다.
마지막은 Rust가하는 일입니다. 이동 은 소스가 정적으로 무효화되는 값에 의한 사용 일 뿐이므로 컴파일러는 현재 유효하지 않은 메모리의 추가 사용을 방지합니다.
let v: Vec<u8> = vec![1, 2, 3];
let w: Vec<u8> = v;
println!("{}", v); // error: use of moved value
소멸자가있는 유형 은 일부 리소스 (예 : 메모리 할당 또는 파일 핸들)에 대한 관리 / 소유권이 있고 바이트 복사가이를 올바르게 복제 할 가능성이 거의 없기 때문에 값으로 사용할 때 (바이트 복사시) 이동 해야합니다. 소유권.
"음 ... 묵시적 카피 란 무엇입니까?"
다음과 같은 기본 유형을 생각해보십시오 u8
. 바이트 복사는 단순하고, 단일 바이트 만 복사하고, 의미 론적 복사는 단순합니다. 단일 바이트를 복사합니다. 특히, 바이트 사본 은 의미 론적 사본입니다. Rust에는 어떤 유형이 동일한 의미 론적 및 바이트 사본을 갖는지 포착 하는 내장 특성도Copy
있습니다.
따라서 이러한 Copy
유형의 값별 사용도 자동으로 의미 론적 복사본이므로 소스를 계속 사용하는 것이 완벽하게 안전합니다.
let v: u8 = 1;
let w: u8 = v;
println!("{}", v); // perfectly fine
올드 다음 NoCopy
마커가 될 수있는 유형의 가정의 컴파일러의 자동 동작을 재정의합니다 Copy
(즉, 오직 프리미티브의 집계를 포함하고 &
)됩니다 Copy
. 그러나 옵트 인 내장 특성 이 구현 되면 변경됩니다 .
위에서 언급했듯이 옵트 인 내장 트레이 트가 구현되므로 컴파일러는 더 이상 자동 동작을 갖지 않습니다. 그러나 과거에 자동 동작에 사용 된 규칙은를 구현하는 것이 합법적인지 확인하는 규칙과 동일합니다 Copy
.