러스트의 기초적인 문법과 언어적 특성을 설명하는 책
책의 내용을 전부 요약하지 않고 언어적 특성, 특이점을 위주로 요약하였다
- 용어
- 크레이트: 러스트의 코드 패키지 명칭
- 카고: 러스트 패키지 관리자
- lock 파일은 재현 가능한 빌드를 위해 매우 중요 → 코드 저장소에 푸시되어야 함
- 패키지: 일련의 기능을 제공하는 하나 이상의 크레이트로 구성된 번들
- 특징
- AOT 언어: JIT 언어와는 다르게 컴파일 즉시 머신 실행 파일이 생성된다
- 정적 타입 언어
- 컴파일 타임에 크기를 알 수 없는 데이터는 스택 대신 힙에 저장한다
- 동적 디스패치보다는 정적 디스패치를 선호하는 언어이다
- 튜플: 여러 타입의 값을 묶어 하나의 복합 타입으로 만드는 일반적인 방법
- 소유권
- 가비지 컬렉터 없이 힙 메모리 안정성을 보장하기 위한 규칙
- 댕글링 포인터: 이미 해제되거나 재 할당되어 잘못된 메모리를 참조하는 포인터
- 컴파일 타임에 크기가 고정되는 타입은 스택에 저장하기 때문에 위 규칙을 무시할 수 있다
- 위 타입들은 전부 copy 라는 trait 을 구현해야 한다
- 특징
- RAII 패턴을 이용하며 수명이 끝나는 시점에 drop 이라는 함수를 자동으로 호출하여 메모리를 해제한다
- 값의 소유자(변수)는 동시에 여럿이 존재할 수 없으며 스코프 밖으로 벗어날 때 값은 버려진다
- 변수 선언 시 얕은 복사(메모리 값 참조)가 아닌 기존 변수를 무효화 하는 이동으로 처리된다
- 참조자(대여)
- 소유권 이동 없이 값을 사용 할 수 있는 기능
- 러스트에서는 해당 기능을 위해 키워드를 제공함
- 참조하는 대상을 수정 할 수 없다
- 역 참조를 통해 실제 값에 접근할 수 있다
- 가변 참조자
- 일반적이 참조자와 달리 변수를 수정 할 수 있는 참조자
- 만약 기존 참조자가 존재한다면 추가로 일반/가변 참조자를 만들 수 없다
- 슬라이스
- 컬렉션의 연속된 일련의 요소만을 참조하여 소유권을 가지지 않는 키워드
- 컬렉션의 일부 요소만을 읽지만 소유권이 필요하지 않을 때 사용된다
- 구조체
- 필드 중 일부만 가변으로 만들 수 없으며 변수 선언 당시 가변 여부가 결정된다
- 연관 함수: 구조체 필드 정의와 달리 메서드는 별도의 블록(impl) 에서 구현한다
- 열거형(enum)
- variant: 하나의 타입이 가질 수 있는 다양한 경우의 수
- 각 variant 가 서로 다른 변수 목록을 가질 수 있다
- 컬렉션
- 힙에 저장되는 데이터 구조로 백터, 스트링, 해시맵 등이 존재한다
- 백터가 버려질 때 해당하는 내용물도 전부 같이 메모리에서 해제된다
- 러스트 해시맵의 해시 함수는 DDOS 공격에 저항하기 위해 SipHash 를 사용한다
- 에러 처리
- 예외(exception)이 존재하지 않고 대신 복구 가능한 에러를 위한 Result<T,E> 타입과 복구 불가능한 panic! 매크로가 존재한다
- panic이 발생하는 경우 backtrace ( 경로의 모든 호출 함수 목록)를 출력하게 할 수 있다
- 실패할지도 모르는 함수는 Result 를 선택하는 편이 좋다
- 어떠한 가정, 보장, 계약, 불변성이 깨지는 경우에는 panic 을 발생시키는 편이 좋다
- 제네릭
- 실제 컴파일 타임에 제네릭 코드를 실제 구체 타입으로 채워진 여러 코드로 변경하는 단형성화 과정을 거친다
- 제네릭 클래스에서 특정 타입 매개변수만 가질 수 있는 함수 정의가 가능하다
- 트레이트
- 특정 타입이 가지고 있으면서 다른 타입과 공유할 수 있는 기능을 정의
- java의 interface와 유사한 형태
- 트레이트나 트레이트를 구현할 타입 둘 중 하나는 반드시 자신의 크레이트여야 한다
- 여러 트레이트를 구현해야 호출이 가능한 함수 정의가 가능하다
- 라이프타임
- 제네릭의 일종으로 컴파일러에게 참조자들이 서로 어떤 관계인지 알려주는데 사용
- 참조자가 필요한 기간 동안 유효함을 보장한다
- 한 함수에서 두 개의 라이프타임 지정이 된다면 더 작은쪽이 구체적인 라이프타임으로 지정된다
- static 라이프타임은 프로그램의 전체 생애주기 동안 살아있음을 표현한다
- 테스트
- 유닛 테스트는 일반 코드와 같은 파일에 위치하기 때문에 #[cfg(test)] 어노테이션으로 컴파일 결과물에 포함되지 않도록 명시해야 한다
- 통합 테스트는 src 폴더와 달리 tests 와 같은 별도의 폴더에 위치시킨다
- 반복자와 클로저
- 클로저: 변수를 저장할 수 있는 함수
- 자신의 환경을 캡처하는 익명함수가 더 명확한 표현으로 생각함
- 통상적으로 짧은 콘텍스트 내에서 사용됨
- 불변, 가변, 소유권 이동으로 캡처할 방법을 지정할 수 있다
- 종류
- FnOnce: 한 번만 호출 할 수 있는 클로저로 캡처된 값을 본문 밖으로 이동시키는 클로저
- FnMut: 캡처된 값을 이동하지는 않지만 값을 변경하는 클로저
- Fn: 캡처된 값을 이동하거나 변경하지 않는 클로저
- 반복자(iterator): 일련의 아이템들을 순서대로 특정 작업을 수행하도록 하는 헬퍼
- 러스트의 비용없는 추상화를 통해 런타임 오버헤드가 없다
- 소비 어댑터: 반복자를 소비하는 next 함수를 내부적으로 호출하는 함수
- 반복자 어댑터: 반복자를 소비하는 대신 작업을 수행 후 다른 반복자를 제공하는 함수
- 스마트 포인터
- 포인터 기능 뿐만 아니라 추가적인 메타데이터와 기능을 가지는 데이터 구조
- 대부분의 포인터는 데이터를 대여하는 참조자와 달리 데이터를 소유한다
- 참조 카운팅: 소유자의 개수를 추적하고 더 이상 소유자가 없으면 데이터를 정리하는 포인터
- 종류
- Box<T>: 스택이 아닌 힙에 데이터를 저장할 수 있도록 하는 포인터
- Rc<T>: 참조자 개수를 추적하여 0이면 메모리를 정리할 수 있도록 하는 포인터
- RefCell<T>: 대여 규칙을 런타임에 집행하고 싶을 때 사용
- 동시성
- 러스트의 객체지향