답변:
String
동적 힙 문자열 유형 Vec
입니다. 문자열 데이터를 소유하거나 수정해야 할 때 사용하십시오.
str
메모리 어딘가에 동적 길이의 UTF-8 바이트의 불변의 1 시퀀스입니다. 크기를 알 수 없으므로 포인터 뒤에서 만 처리 할 수 있습니다. 이 수단 str
가장 일반적으로 이 같이 나타납니다 &str
: 일부 UTF-8 데이터에 대한 참조는 일반적으로 "문자열 슬라이스"또는 단지 "조각"이라고합니다. 슬라이스 는 일부 데이터에 대한보기 일 뿐이며 해당 데이터는 어디든있을 수 있습니다 (예 :
"foo"
은입니다 &'static str
. 데이터는 실행 파일로 하드 코딩되고 프로그램이 실행될 때 메모리로로드됩니다.String
: 의 데이터 보기 를 String
역 참조합니다&str
String
.스택에서 : 예를 들어 다음은 스택 할당 바이트 배열을 만든 다음 해당 데이터&str
의 뷰를 다음과 같이 가져옵니다 .
use std::str;
let x: &[u8] = &[b'a', b'b', b'c'];
let stack_str: &str = str::from_utf8(x).unwrap();
요약하면, String
문자열을 다른 스레드에 전달하거나 런타임에 빌드하는 등 소유 한 문자열 데이터가 필요한 경우 사용 하고 문자열 &str
보기 만 필요한 경우 사용 하십시오.
이것은 벡터 Vec<T>
와 슬라이스 &[T]
사이의 관계와 동일 하며 일반 유형에 대한 값별 T
및 참조 별 관계와 유사합니다 &T
.
1 A는 str
고정 길이이다; 끝을 넘어서 바이트를 쓰거나 뒤에 유효하지 않은 바이트를 남겨 둘 수 없습니다. UTF-8은 가변 너비 인코딩이기 때문에 str
많은 경우 효과적으로 모든 s를 변경할 수 없습니다. 일반적으로, 돌연변이는 이전보다 더 많거나 적은 바이트를 쓰도록 요구합니다 (예를 들어 a
(1 바이트)를 ä
(2+ 바이트)로 바꾸려면 더 많은 공간을 확보해야합니다 str
). &str
제자리를 수정할 수있는 특정 방법이 있습니다 . 대부분 ASCII 문자 만 처리 하는 방법이 있습니다 make_ascii_uppercase
.
(2 개) 동적 크기 유형 과 같은 것들을 허용 Rc<str>
녹 1.2 이후 UTF-8 바이트 카운트 기준의 시퀀스를. Rust 1.21을 사용하면 이러한 유형을 쉽게 만들 수 있습니다.
[u8; N]
.
Rc<str>
그리고 Arc<str>
지금은 표준 라이브러리를 통해 사용할 수 있습니다.
나는 C ++ 배경이 내가 생각하는 것이 매우 유용하다고 String
및 &str
C ++ 측면에서 :
String
같다 std::string
; 메모리를 소유하고 메모리를 관리하는 더티 작업을 수행합니다.&str
유사한이다 char*
(그러나 좀 더 정교한); 의 내용에 대한 포인터를 얻는 것과 같은 방식으로 청크의 시작을 가리 킵니다 std::string
.둘 다 사라질까 요? 난 그렇게 생각하지 않아. 그들은 두 가지 목적을 제공합니다.
String
버퍼를 유지하고 사용하는 것이 매우 실용적입니다. &str
가벼우 며 문자열을 "보는"데 사용되어야합니다. 새 메모리를 할당하지 않고도 청크를 검색, 분할, 구문 분석 및 교체 할 수 있습니다.
&str
String
문자열 리터럴을 가리킬 수 있으므로 내부를 볼 수 있습니다. 다음 코드는 리터럴 문자열을 String
관리 메모리 에 복사해야합니다 .
let a: String = "hello rust".into();
다음 코드를 사용하면 리터럴 자체를 복사하지 않고 사용할 수 있습니다 (읽기 전용).
let a: &str = "hello rust";
그들은 실제로 완전히 다릅니다. 우선, a str
는 유형 수준에 지나지 않습니다. 소위 동적 크기 유형 (DST)이기 때문에 유형 수준에서만 추론 할 수 있습니다. str
테이크 업 크기는 컴파일 타임에 알 수 없으며 런타임 정보에 따라 다릅니다. 컴파일러는 컴파일 타임에 각 변수의 크기를 알아야하기 때문에 변수에 저장할 수 없습니다. A str
는 개념 상 단지 u8
UTF-8의 유효한 형식을 보장하는 바이트 행입니다 . 행이 얼마나 큽니까? 런타임까지 아무도 모르므로 변수에 저장할 수 없습니다.
흥미로운 점은 런타임에 &str
또는 기타 유사한 포인터 가 존재 한다는 str
것 입니다. 소위 "팻 포인터"입니다. 추가 정보 (이 경우 가리키는 대상의 크기)가있는 포인터이므로 두 배가 큽니다. 실제로 a 는 a 에 가깝지만 (a는 아님). A 는 두 단어입니다. a의 첫 바이트에 대한 하나의 포인터와를 나타내는 바이트 수를 나타내는 다른 숫자 .Box<str>
&str
String
&String
&str
str
str
말한 것과 달리, a str
는 불변 일 필요는 없다. 에 &mut str
대한 배타적 포인터로를 얻을 수 있다면 str
, 그것을 바꿀 수 있고 그것을 바꿀 수있는 모든 안전한 함수는 UTF-8 제약 조건이 유지되도록 보장합니다. 왜냐하면 위반되면 라이브러리 가이 제약 조건이 true이며 확인하지 않습니다.
그래서 무엇 String
입니까? 그것은 세 단어입니다. 두 개는 동일 &str
하지만 str
힙에 버퍼 의 용량 인 세 번째 단어를 추가합니다. 항상 힙에 str
채워져 있기 전에 항상 힙 (a 는 반드시 힙에있는 것은 아님)으로 채워져 다시 할당해야합니다. String
기본적으로 소유 을 str
그들이 말하는대로; 그것은 그것을 제어하고 크기를 조정하고 적합하다고 판단되면 재 할당 할 수 있습니다. 따라서 a String
는 a &str
보다 가까이에 str
있습니다.
또 다른 것은 Box<str>
; 이것은 또한 a를 소유 str
하고 런타임 표현은 a 와 동일 &str
하지만 그것 str
과 는 달리 소유 &str
하지만 용량을 모르기 때문에 크기를 조정할 수 없으므로 기본적으로 크기를 조정할 수없는 Box<str>
고정 길이로 볼 String
수 있습니다 String
크기를 조정하려면 항상로 변환하십시오 ).
매우 유사한 관계 사이에 존재 [T]
하고 Vec<T>
아무 UTF-8 제약이없고, 그 크기가 동적 아닌 임의의 유형을 지정할 수 제외.
str
타입 레벨에서 의 사용 은 주로 &str
; 특성을 편리하게 쓸 수 있도록 유형 수준에 존재합니다. 이론적 str
으로는 유형의 것이 존재할 필요는 &str
없었지만 이제는 일반적 일 수있는 많은 추가 코드를 작성해야합니다.
&str
String
복사하지 않고 여러 개의 서로 다른 하위 문자열을 가질 수있는 것이 매우 유용합니다 . 등은 말했다 String
소유 을 str
가 관리 힙에 당신 만의 문자열을 만들 수 있다면 String
새로운으로 String
는 녹에 모든 전용 메모리 안전을 다루는 하나 개의 소유자를 가질 수 있기 때문에 복사해야합니다. 예를 들어 문자열을 슬라이스 할 수 있습니다.
let string: String = "a string".to_string();
let substring1: &str = &string[1..3];
let substring2: &str = &string[2..4];
str
동일한 문자열의 두 개의 다른 하위 문자열이 있습니다. 힙 string
에서 실제 전체 str
버퍼 를 소유하고 &str
하위 문자열은 힙 에서 해당 버퍼에 대한 팻 포인터입니다.
std::String
단순히의 벡터입니다 u8
. 소스 코드 에서 정의를 찾을 수 있습니다 . 힙 할당 및 확장 가능합니다.
#[derive(PartialOrd, Eq, Ord)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct String {
vec: Vec<u8>,
}
str
string slice 라고도하는 기본 유형 입니다. 문자열 슬라이스의 크기는 고정되어 있습니다. 리터럴 문자열 let test = "hello world"
에는 &'static str
유형이 있습니다. test
이 정적으로 할당 된 문자열에 대한 참조입니다.
&str
예를 들어, 수정할 수 없습니다
let mut word = "hello world";
word[0] = 's';
word.push('\n');
str
&mut str
예를 들어 다음과 같이 가변 슬라이스가 있습니다 .
pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str)
let mut s = "Per Martin-Löf".to_string();
{
let (first, last) = s.split_at_mut(3);
first.make_ascii_uppercase();
assert_eq!("PER", first);
assert_eq!(" Martin-Löf", last);
}
assert_eq!("PER Martin-Löf", s);
그러나 UTF-8을 조금만 변경하면 바이트 길이가 변경 될 수 있으며 슬라이스는 해당 참조를 재 할당 할 수 없습니다.
간단히 말해서, String
데이터 유형은 (와 마찬가지로 Vec
) 힙에 저장 되며 해당 위치에 액세스 할 수 있습니다.
&str
슬라이스 유형입니다. 즉 String
, 힙에 이미 존재한다는 의미 입니다.
&str
런타임에 할당을 수행하지 않습니다. 따라서 메모리상의 이유로 &str
over 을 사용할 수 있습니다 String
. 그러나 사용시 &str
명시 적 수명을 다룰 수 있음을 명심하십시오 .
str
는 view
이미 String
힙에 존재 한다는 것 입니다 .
C # 및 Java 사용자의 경우 :
String
===StringBuilder
&str
=== (불변) 문자열나는 &str
Java / C #의 인터 닝 된 문자열과 같이 문자열을 볼 수있는 뷰로 생각 하고 싶습니다. 변경 할 수 없으며 새로운 것을 생성하십시오.
다음은 빠르고 쉬운 설명입니다.
String
-확장 가능하고 소유 가능한 힙 할당 데이터 구조. 에 강제 할 수 있습니다 &str
.
str
-힙 (heap) 또는 이진 (binary)에있는 가변 길이의 고정 길이 문자열 (현재 Rust가 발전함에 따라)입니다. 과 str
같은 문자열 슬라이스보기를 통해서만 빌린 유형으로 상호 작용할 수 있습니다 &str
.
사용 고려 사항 :
String
문자열을 다른 스레드에 전달하는 등 문자열을 소유하거나 변경하려는 경우 선호 하십시오.
&str
문자열의 읽기 전용보기를 원하는 경우 선호 하십시오.
&str
두 가지 구성 요소로 구성됩니다 : 일부 바이트에 대한 포인터와 길이를."