strings

Hunter_Joe·2023년 8월 7일
0

Rust 기초

목록 보기
6/8

what are strings?

  • string은 일련의 unicode 문자이다.
  • Rust에서 문자열은 다른 프로그래밍 언어의 문자열과 달리 null로 종료되지 않는다.
  • 오히려 null문자를 포함할 수 있다.

note


type of strings

1. string literal(&str)

  • primitive type
  • immutable
  • fixed-length string stored somewhere in memory
    메모리 어딘가에 저장된 고정길이의 문자열
  • value of string is known at compile time
    문자열의 값은 컴파일 시간에 알려져 있음

note

  • a string literal is also known as a string slice

1-1 create string literal

let language = "Rust";
-----------------------
* rust <= string value
* string은 쌍따옴표로 묶여있음

example

fn main() {
	let language:&str = "rust";
    println!("String literal : {}", language);
    println!("Length of the string literal : {}", language.len());
}

note
- .len() : string literal or string object의 길이를 찾는 내장 함수

2. string object(string)

  • a string is encoded as a UTF-8 sequence
    문자열은 UTF-8시퀀스로 인코딩 됨
  • Heap-allocated data structure
  • the size of this string can be modified
  • not null-terminated
  • encode string values that are given at the run time
  • heap-allocated data structure

Heap-allocated data structure는 프로그램의 실행 도중 동적으로 메모리를 할당하고 사용하는 자료 구조를 의미합니다. 이러한 자료 구조는 '힙(heap)'이라는 메모리 영역에 할당되며, 사용이 끝나면 명시적으로 메모리를 해제해야 합니다.

힙(heap)은 컴퓨터 메모리의 두 번째 중요한 영역 중 하나로, 정적인 데이터 영역인 스택(stack)과는 달리 동적인 데이터를 저장하는 영역입니다. 힙 영역은 프로그램의 실행 중에 런타임에 메모리 할당과 해제가 이루어지며, 주로 다음과 같은 자료 구조들이 힙에 할당됩니다.

  1. 동적 배열(Dynamic Array): 동적 배열은 크기가 동적으로 조절되는 배열로, 필요에 따라 크기를 늘리거나 줄일 수 있습니다. ArrayList나 Vector 등이 동적 배열의 예시입니다.

  2. 동적 연결 리스트(Dynamic Linked List): 연결 리스트는 노드로 이루어진 자료 구조로, 노드들이 포인터를 통해 서로 연결되어 있습니다. 동적으로 노드를 추가하거나 삭제할 수 있어 유연한 데이터 구조입니다.

  3. 힙(heap) 자료 구조: 자료들이 우선순위에 따라 정렬되는 힙(heap)은 주로 우선순위 큐(priority queue)를 구현하는 데 사용됩니다. 최소 힙과 최대 힙이 있으며, 각각 부모 노드가 자식 노드보다 작거나 큰 조건을 만족합니다.

  4. 해시 맵(Hash Map) 및 해시 테이블(Hash Table): 해시 맵은 이미 설명한 것처럼 키-값 쌍을 저장하는 자료 구조로, 동적으로 크기가 조절되는 경우가 많습니다.

  5. 트리(Tree) 자료 구조: 이진 트리, AVL 트리, 레드-블랙 트리 등 여러 종류의 트리 구조도 힙 영역에서 할당되며 동적으로 변경될 수 있습니다.

힙 영역에서 할당된 데이터 구조들은 사용이 끝난 후 명시적으로 메모리를 해제해야 합니다. 이를 잊어버리거나 제대로 처리하지 않으면 메모리 누수(memory leak)가 발생할 수 있어, 프로그램의 성능 저하나 안정성 문제를 초래할 수 있습니다.

2-1 empty string object

  • .to_string() : method
  • empty String or String literal을 String object로 전환
let lang = String::new();

let s_lang = lang.to_string();

2-2 initialized string object

  • from() : method
  • from() 메서드에 전달된 기본값을 사용하여 문자열을 생성
let lang = String::from("Rust");

-string literal을 생성한 후 string object로 전환

let lang = "Rust";
let S_lang = lang.to_string();

example

fn main() {
  // create an empty String
  let course1 = String::new();
  // convert String literal to String object using .to_string
  let s_course1 = course1.to_string();
  // print the String object
  println!("This is an empty string {}.", s_course1);
  // print the length of an empty String  object
  println!("This is a length of my empty string {}.", s_course1.len());

  // create a String literal
  let course2 = "Rust Programming";
  // convert String literal to string object using .to_string
  let s_course2 = course2.to_string();
  // print the String object
  println!("This is a string literal : {}.", s_course2);
  // print the length of a String object
  println!("This is a length of my string literal {}.", s_course2.len());

  // define a String object using from method
  let course3 = String::from("Rust Language");
  // print the String object
  println!("This is a string object : {}.", course3);
  // print the length of an string object
  println!("This is the length of my string object {}.", course3.len());
}

core methods of string objects

1. capacity in bytes

  • capacity()
  • String에 할당된 바이트 수를 제공

note

  • String의 길이는 항상 용량(capacity)보다 작거나 같음

syntax

str.capacity()

example

fn main() {
	let course = String::from("rust");
    println!("This is a beginner course in {}.", course);
    //capacity in bytes
    println!("Capacity: {}.", course.capacity());
}

2. finding a substring

  • contains() : built-in func(내장 함수)
  • 하나의 문자열에 다른 문자열이 포함되어있는지 확인 가능

syntax

str.contains("sub_str")

example

fn main() {
  // define a growable string variable
  let str = String::from("Rust Programming"); 
  let sub_str = String::from("Rust"); 
  
  println!("This is a beginner course in {}.", str);
  // find if string contains a substring
  println!("{} is a substring of {}: {}.", sub_str, str, str.contains("Rust"));
}

3. replace a substring

  • replace() : built in-function
  • string object 내의 모든 부분 문자열을 다른 문자열로 바꿀 때

syntax

str.replace(replace_from, replace_to)

example

fn main() {
  // define a growable string variable
  let str = String::from("Rust Programming"); 
  let replace_from = "Programming";
  let replace_to = "Language"; 
  // find if string contains a substring
  let result = str.replace(replace_from, replace_to);
  println!("{} now becomes {}.", str, result);
}

4. trim a string

  • string.trim()
  • 문자열에서 선행 및 후행 공백을 제거하는 데 사용

syntax

string.trim()

example

fn main() {
   let string = "   Rust     Programming     ".to_string();
   let trim_string = string.trim(); 
   // get characters at 5,6,7,8,9,10 and 11 indexes
   println!("Trimmed_string : {}", trim_string);
}

note

  • trim 내장함수는 문자열 사이의 공백은 지우지 않음

iterating over strings

  • 문자열 반복

1. tokenizing a string object

  • string object는 공백이나 char token으로 토큰화 될 수 있음

1.1 tokenizing to separate on whitespaces

  • split_whitespace()
  • 공백이 발생하는 구간에서 나눠주는 역할을 함
  • for루프를 사용하여 문자열을 반복하여 공백에서 분할

syntax

for found in str.split_whitespace(){
	println!("{}", found);
}

example

fn main() {
  // define a String object
  let str = String::from("Rust Programming"); 
  // split on whitespace
  for token in str.split_whitespace(){
      println!("{}", token);
  }
}
--------------------------------------------
*console

Rust
Programming

1.2 tokenizing to split on a custom character

  • split : method
  • token으로 부터 문장을 분할하는데 사용됨
  • 쉼표로 구분된 데이터를 처리하는데 유용

syntax

for found in str.split(",") {
	println!("{}", found);
}

example

fn main() {
	let str = String::from("Educative, course on, Rust, Programming");
    for token in str.split(","){
    	println!("{}",token);
    }
}

2. iterating over the string object

  • chars : method
  • for 루프를 사용하여 문자열의 각 요소를 반복가능

syntax

for found in str.chars(){
	println!("{}", found);
}

example

fn main() {
  // define a String object
  let str = String::from("Rust Programming");  
  // split on literal
  for token in str.chars(){
      println!("{}", token);
  }
}
--------------------------------------------
*console 
R
u
s
t

P
r
o
g
r
a
m
m
i
n
g

updating a string

note

  • Q. 기존 문자열을 업데이트하는 대신 새 문자열을 만드는 것은 어떤가요?
    A. 기존 문자열 업데이트는 조건에 따라 문자열이 변경되는 상황에서 컴파일하는 대신 런타임에 기존 문자열을 변경하려는 경우에 유용

1. push a single character

  • push() : method

example

fn main() {
	let mut course = String::from("Rus");
    //push a character 
    coures.push('t');
    println!("This is a beginner course in {}.", course);
}

2. push a string

  • push_str()

example

fn main() {
  // define a string object
  let mut course = String::from("Rust");
  // push a string
  course.push_str(" Programming");
  println!("This is a beginner course in {}.", course);
}

3. concatenation using + operator

  • 문자열은 +연산자를 사용해 다른 문자열에 연결할 수 있음

example

#[allow(unused_variables, unused_mut)]
fn main(){
   // define a String object 
   let course = "Rust".to_string();
   // define a String object
   let course_type = " beginner course".to_string();
   // concatenate using the + operator
   let result = course + &course_type;
   println!("{}", result);
}

note

  • The right-hand-side operand is to borrowed while concatenating using + operator.
    오른쪽 피연산자는 +연산자를 사용하여 연결하는 동안 차용됨

Rust에서의 주인개념

rust에서 owner이란? 
-특정 데이터나 값에 대한 소유권을 가진 변수 

***Example***
fn main() {
    let s1 = String::from("Hello, ");
    let s2 = String::from("world!");

    let s3 = s1 + &s2;

    println!("{}", s3);
}

위 코드에서 s1s2는 각각 문자열 Hello, "과 world!의 주인(owner)
s1의 문자열은 '+' 연산자를 사용하여 s2의 문자열과 결합되어 s3에 저장됨 그런데 s1은 더 이상 사용되지 않기 때문에 s3로 소유권이 이전되고, s1은 무효화


format marco

  • format!
  • 두개 이상의 String objects를 더할 때 씀
  • 변수 또는 값을 가져와 단일 문자열로 병합

note

  • format! 매크로는 원하는 순서대로 연결하기 위해 플레이스홀더({}) 내에 양의 정수를 전달하여 사용할 수 있습니다. 만약 숫자가 명시되지 않으면 값이 작성된 순서대로 연결됩니다.
  • format!매크로 결과를 표시하려면 결과를 변수에 저장해야 합니다.

example

fn main(){
  
   let course = "Rust".to_string();
   let _course_type = "beginner course".to_string();
   // default format macro 
   let result = format!("{} {}", course, _course_type);
   // passing value in the placeholder in the format macro 
   let result = format!("{1} {0}", course,_course_type);
   println!("{}", result);
}
-------------------------------
* console 
beginner course Rust

slicing a string

  • slicing은 문자열 값의 일부를 가져오는 데 사용

syntax

let slice = &string[start_index..end_index]

note

  • start_index는 포함, end_index는 제외
  • start_index의 최소값 = 0
    end_index의 최댓값 = 문자열의 크기

example

fn main() {
   let string = "Rust Programming".to_string();
   let slice = &string[5..12]; 
   // get characters at 5,6,7,8,9,10 and 11 indexes
   println!("Slice : {}", slice);
}

function and strings

passing primitive string - string literal(str)

  • 문자열 리터럴은 다른 변수와 마찬가지로 함수에 전달됨.
  • 함수 호출 후에 재사용할 수 있음.

example

fn main(){
   let course: &str = "Rust Programming";
   display_course_name(course); 
   println!("{}",course); // string literal is used after the function call
}
fn display_course_name(my_course: &str){
   println!("Course : {}", my_course);
}

passing growable string - string object(string)

  • 문자열 개체를 함수에 전달하는 동안 한 번 전달된 값이 해당 함수의 범위로 이동되어 재사용할 수 없기 때문에 다시 재사용할 수 없음 (추후)

example

fn main(){
   let course:String = String::from("Rust Programming");
   display_course_name(course); 
   //cannot access course after display
}
fn display_course_name(my_course:String){
   println!("Course : {}", my_course);
}
------------------------------------
*console
Course : Rust Programming
profile
hunting season

0개의 댓글