Rust에서 "기본 유형"이란 무엇입니까?


37

어딘가에서 "기본 유형"(및 그 속성 #[fundamental]) 이라는 용어를 선택했고 지금 막 그것에 대해 더 많이 배우고 싶었습니다. 어떤 상황에서는 일관성 규칙을 완화하는 것에 대해 막연하게 기억합니다. 그리고 참조 유형이 기본 유형이라고 생각합니다.

불행히도, 웹 검색은 그리 멀지 않았습니다. Rust 참조는 (내가 볼 수있는 한) 언급하지 않습니다. 방금 튜플의 기본 유형속성을 도입 한 RFC 에 관한 문제를 발견 했습니다 . 그러나 RFC에는 기본 유형에 대한 단일 단락이 있습니다.

  • #[fundamental]유형 Foo에 걸쳐 담요 IMPL을 구현하는 하나입니다 Foo주요 변경입니다. 로서 설명, &&mut기본이다. 이 속성은에 적용 되며 일관성 과 동일 Box하게 Box동작합니다 .&&mut

나는 그 표현을 이해하기가 상당히 어렵다는 것을 알고 기본 유형에 대한이 비트를 이해하기 위해 전체 RFC에 대한 심층적 인 지식이 필요하다고 느낍니다. 나는 누군가가 기본 유형을 다소 간단한 용어로 설명 할 수 있기를 바랐습니다 (물론 지나치게 단순화하지는 않음). 이 질문은 찾기 쉬운 지식의 역할도합니다.

기본 유형을 이해하기 위해 다음 질문에 대답하고 싶습니다 (물론 "무엇입니까?"라는 질문 외에도).

  • 기본 유형이 기본이 아닌 유형보다 더 많은 기능을 수행 할 수 있습니까?
  • 라이브러리 작성자로서 내 유형 중 일부를로 표시하면 어떤 방식으로 혜택을 얻을 수 #[fundamental]있습니까?
  • 핵심 언어 또는 표준 라이브러리의 어떤 유형이 기본입니까?

답변:


34

일반적으로 라이브러리에 generic 유형이있는 Foo<T>경우 T로컬 유형 인 경우에도 다운 스트림 크레이트는 특성을 구현할 수 없습니다 . 예를 들어

( crate_a)

struct Foo<T>(pub t: T)

( crate_b)

use crate_a::Foo;

struct Bar;

// This causes an error
impl Clone for Foo<Bar> {
    fn clone(&self) -> Self {
        Foo(Bar)
    }
}

놀이터에서 작동하는 (즉 오류가 발생하는) 구체적인 예를 들어,

use std::rc::Rc;

struct Bar;

// This causes an error
// error[E0117]: only traits defined in the current crate
// can be implemented for arbitrary types
impl Default for Rc<Bar> {
    fn default() -> Self {
        Rc::new(Bar)
    }
}

(운동장)


이것은 일반적으로 상자 제작자가 다운 스트림 상자를 파괴하지 않고 특성의 (담요) 구현을 추가 할 수있게합니다. 유형이 특정 특성을 구현 해야하는지 확실하지 않은 경우에 좋지만 나중에 유형을 지정해야합니다. 예를 들어, 처음부터 특성을 구현하지 않는 일종의 숫자 유형이있을 수 있습니다 num-traits. 이러한 특성은 나중에 근본적인 변경없이 추가 할 수 있습니다.

그러나 경우에 따라 도서관 저자는 다운 스트림 상자가 특성을 구현할 수 있기를 원합니다. 이것은 #[fundamental]속성이 들어오는 곳 입니다. 유형에 배치 할 때 해당 유형에 대해 현재 구현되지 않은 특성은 구현되지 않습니다 (속성 변경 금지). 결과적으로, 다운 스트림 크레이트는 유형 매개 변수가 로컬 인 한 해당 유형에 대한 특성을 구현할 수 있습니다 (이 유형으로 계산할 유형 매개 변수를 결정하는 복잡한 규칙이 있습니다). 기본 유형은 주어진 특성을 구현하지 않기 때문에 일관성 특성을 유발하지 않고 해당 특성을 자유롭게 구현할 수 있습니다.

예를 들어, Box<T>로 표시되어 #[fundamental]있으므로 Rc<T>위 코드와 유사한 다음 코드가 작동합니다. Box<T>구현하지 않는 Default(하지 않는 T구현 Default우리가 그렇지 않은 미래에 있기 때문에이된다고 가정 할 수 있습니다) Box<T>기본이다. 구현 있습니다 Default에 대한 것은 Bar그 이후, 문제가 발생할 것이라고 Box<Bar>이미 구현 Default.

struct Bar;

impl Default for Box<Bar> {
    fn default() -> Self {
        Box::new(Bar)
    }
}

(운동장)


반면에 특성은로 표시 할 수도 있습니다 #[fundamental]. 이것은 기본 유형에 대한 이중 의미를 갖습니다. 어떤 유형이 현재 기본 특성을 구현하지 않는 경우 해당 유형이 향후에이를 구현하지 않을 것이라고 가정 할 수 있습니다 (다시 말해서 주요 변경 사항 제외). 이것이 실제로 어떻게 사용되는지 잘 모르겠습니다. 코드 (아래 링크)에서 FnMut정규 표현식 (약 무언가)에 필요하다는 메모와 함께 기본으로 표시되어 &str: !FnMut있습니다. regex상자에서 사용 된 곳이나 다른 곳에서 사용 된 곳을 찾을 수 없습니다 .

이론적으로, Add특성이 기본 (논의 된) 것으로 표시 되었다면, 이것이 아직없는 것들 사이에 추가를 구현하는 데 사용될 수 있습니다. 예를 들어, [MyNumericType; 3]특정 상황에서 유용 할 수있는 (포인트 방식)을 추가 하는 것은 물론 ( [T; N]기본적으로 만드는 것도 가능합니다).


원시 기본적인 유형은 &T, &mut T(참조 여기에 일반적인 기본 유형 모두의 데모). 표준 라이브러리에서, Box<T>그리고 Pin<T>또한 기본적으로 표시됩니다.

표준 라이브러리의 기본적인 특성은 Sized, Fn<T>, FnMut<T>, FnOnce<T>Generator.


점을 유의 #[fundamental]속성이 현재 불안정합니다. 추적 문제는 이슈 # 29635 입니다.


1
좋은 대답입니다! 기본 유형에 대해서는 : 소수에 불과 일반적인 기본 유형이있다 : &T, &mut T, *const T, *mut T, [T; N], [T], fn포인터와 튜플. 그리고 그것들을 모두 테스트하면 (이 코드가 이해가 안된다면 알려주십시오) 참조가 유일한 기본 프리미티브 유형 인 것 같습니다 . 흥미 롭군 다른 사람들, 특히 원시 포인터가 아닌 이유를 아는 데 관심이 있습니다. 그러나 그것은이 질문의 범위가 아닙니다.
Lukas Kalbertodt

1
@LukasKalbertodt 기본 유형에 대한 정보를 주셔서 감사합니다. 테스트에 추가했습니다. 참조 대 포인터에 대한 이론적 근거 는 RFC 풀 요청 에서이 주석 을 확인하십시오 .
SCappella

참조에 불안정한 속성이 문서화되어 있지 않으므로 해당 속성을 찾지 못했습니다.
Havvy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.