반응형

■ 스트링

스트링은 바이트의 컬렉션 및 바이트들을 텍스트로 통역할 때 유용한 기능을 제공하는 몇몇 메소드로 구현되어 있으며, 문자열 데이터를 갖습니다.


◆ 스트링 생성

스트링을 생성하는 방법은 세가지입니다.

 

첫번째, String 구조체의 new 함수를 활용한 생성

 

두번째, String 구조체의 from 함수를 활용한 생성

 

세번째, Display 트레잇이 구현된 모든 타입에서 to_string 메소드를 이용한 생성  

fn main(){
    // 공백 문자열 생성
    let s1 = String::new();

    // 공백 문자열 생성
    let s1 = String::from("");

    // 공백 문자열 생성
    let s1 = "".to_string();
}

◆ 스트링 갱신

스트링을 갱신하는 방법은 네가지 입니다.

 

첫번째, push_str 함수를 활용한 문자열 추가

 

두번째, push 함수를 활용한 문자 추가

 

세번째, + 연산자를 활용한 문자열 접합

 

네번째, format! 매크로를 활용한 문자열 접합

fn main(){
    // 공백 문자열 생성
    let mut s1 = String::from("");

    // push_str 함수로 문자열 추가
    s1.push_str("A");
    println!("String : {}", s1);

    // push 함수로 문자 추가
    s1.push('B');
    println!("String : {}", s1);

    // + 연산자로 문자열 추가
    s1 = s1 + "C";
    println!("String : {}", s1);

    // format! 매크로로 문자열 추가
    s1 = format!("{}{}",s1, String::from("D"));
    println!("String : {}", s1);
}

▶ 출력 결과

String : A
String : AB
String : ABC
String : ABCD
반응형
반응형

■ 벡터

벡터는 데이터량이 컴파일 타임에 결정되지 않아도 되며, 프로그램 실행 시 늘어나거나 줄어들 수 있기 때문에 힙에 저장됩니다. 또한 메모리 상에 서로 이웃하도록 모든 값을 단일 데이터 구조 안에 하나 이상의 값을 저장하도록 해줍니다. 벡터는 같은 타입의 값만을 저장할 수 있으며, 벡터는 스코프 밖으로 벗어날 시 해제됩니다.


◆ 벡터 생성

벡터를 생성하는 방법은 두 가지입니다.

 

첫번째, 제네릭을 통한 데이터 타입 설정과 Vec 구조체의 new 함수를 통한 벡터 생성 

 

두번째, vec! 매크로를 통한 벡터 생성

fn main(){
    // new 함수를 활용하여 벡터 생성
    let v1 : Vec<u32> = Vec::new();

    // vec! 매크로를 활용하여 벡터 생성
    let v2 : Vec<u32> = vec![1,2,3,4,5];
}

◆ 벡터 요소 읽기

벡터 내의 요소를 읽기 위한 방법은 두 가지입니다.

 

첫번째, 참조자(&) 또는 대괄호([])와 인덱스를 활요한 (인덱스를 벗어날 경우 프로그램이 panic 상태가 될 수 있으니 주의가 필요합니다.)

 

두번째, get 함수에 인덱스 파라미터를 넘김으로써 요소에 접근하며, 반환값으로 Option<&T>를 얻습니다.(인덱스를 벗어날 경우 None이 반환됩니다.)

fn main(){
    let v = vec![10, 20, 30];
    println!("첫번째 요소 : {}", &v[0]);
    println!("두번째 요소 : {:?}", v.get(1));
}

▶ 출력 결과

첫번째 요소 : 10
두번째 요소 : Some(20)

◆ 벡터 요소 추가

벡터를 생성하고 push 함수를 활용하여 요소를 추가합니다.

fn main(){
    // new 함수를 활용하여 벡터 생성
    let mut v1 : Vec<u32> = Vec::new();

    // push 함수를 통해 데이터 추가
    v1.push(1);
    v1.push(2);
    v1.push(3);

    println!("Vec : {:?}", v1);
}

▶ 출력 결과

Vec : [1, 2, 3]

◆ 벡터 요소 수정

벡터의 요소를 수정하기 위해서는 선언 및 초기화시 mut 접두어를 붙여줍니다. 벡터 내의 요소를 수정하는 방법은 두가지입니다.

 

첫번째, 대괄호([])와 인덱스를 활용한 수정

fn main(){
    let mut v = vec![10,20,30];

    println!("첫번째 요소 수정 전 : {}", v[0]);
    
    // 첫번째 요소 수정
    v[0] = 11;

    println!("첫번째 요소 수정 후 : {}", v[0]);
}

▶ 출력 결과

첫번째 요소 수정 전 : 10
첫번째 요소 수정 후 : 11

두번째, 참조(&)와 역참조(*)를 활용한 수정

fn main(){
    let mut v = vec![10,20,30];
    println!("수정 전 : {:?}", v);
    
    // 전체 요소 수정
    for i in &mut v{
        *i += 100;
    }
    println!("수정 후 : {:?}", v);
}

▶ 출력 결과

수정 전 : [10, 20, 30]
수정 후 : [110, 120, 130]
반응형
반응형

■ 패턴 매칭

패턴 매칭에는 match 연산자와 if let 문법이 있습니다.

match 연산자는 다양한 조건을 처리할 때 주로 사용되며, if let 문법은 간결한 흐름을 통해 하나의 패턴만 매칭시키고 나머지는 무시하고 싶을 때 사용됩니다.


◆ match

match는 리터럴 값, 변수명 등 다양한 패턴으로 구성될 수 있습니다.

Java, Go 등에서 자주 사용되는 switch 문법과 유사한 기능을 제공합니다.

match의 패턴은 조건이 될 수 있는 모든 항목을 정의해야 합니다. 만약 패턴 조건에서 무시해도 되는 항목에 경우 변경자(_)를 통해 일괄적으로 무시할 수 있습니다.

1) 반환값이 없는 match

#[derive(Debug)]
enum Gender{
    Male,
    Female,
}

#[derive(Debug)]
enum Info{
    Name(String),
    Age(u32),
    Location{x : i32, y : i32},
    Gender(Gender)
}

fn show_info(info : Info) {
    match info {
        Info::Name(s) => println!("Name: {}", s),
        Info::Age(u) => println!("Age : {}", u),
        Info::Location{x, y} => println!("Location x : {}, y : {}", x, y),
        Info::Gender(gender) => println!("Gender : {:?}", gender)
    }
}

fn main(){
    show_info(Info::Name(String::from("Hyunmin Han")));
    show_info(Info::Age(29));
    show_info(Info::Location{x : 130, y : 80});
    show_info(Info::Gender(Gender::Male));
}

▶ 출력 결과

Name: Hyunmin Han
Age : 29
Location x : 130, y : 80
Gender : Male

2) 반환값이 있는 match

#[derive(Debug)]
enum Gender{
    Male,
    Female,
}

#[derive(Debug)]
enum Info{
    Name(String),
    Age(u32),
    Location{x : i32, y : i32},
    Gender(Gender)
}

fn show_info(info : Info) -> String {
    match info {
        Info::Name(s) => {
            println!("Name: {}", s);
            String::from("Name")
        },
        Info::Age(u) => {
            println!("Age : {}", u);
            String::from("Age")
        },
        Info::Location{x, y} => {
            println!("Location x : {}, y : {}", x, y);
            String::from("Location")
        },
        Info::Gender(gender) => {
            println!("Gender : {:?}", gender);
            String::from("Gender")
        }
    }
}

fn main(){
    let s = show_info(Info::Name(String::from("Hyunmin Han")));
    println!("Select Info : {}\n", s);
    let s = show_info(Info::Age(29));
    println!("Select Info : {}\n", s);
    let s = show_info(Info::Location{x : 130, y : 80});
    println!("Select Info : {}\n", s);
    let s = show_info(Info::Gender(Gender::Male));
    println!("Select Info : {}\n", s);
}

▶ 출력 결과

Name: Hyunmin Han
Select Info : Name

Age : 29
Select Info : Age

Location x : 130, y : 80
Select Info : Location

Gender : Male
Select Info : Gender

3) ( _ ) 변경자 활용

#[derive(Debug)]
enum Gender{
    Male,
    Female,
}

#[derive(Debug)]
enum Info{
    Name(String),
    Age(u32),
    Location{x : i32, y : i32},
    Gender(Gender)
}

fn show_info(info : Info) {
    match info {
        Info::Name(s) => println!("Name: {}", s),
        _ => println!("Something")
    }
}

fn main(){
    show_info(Info::Name(String::from("Hyunmin Han")));
    show_info(Info::Age(29));
    show_info(Info::Location{x : 130, y : 80});
    show_info(Info::Gender(Gender::Male));
}

▶ 출력 결과

Name: Hyunmin Han
Something
Something
Something

◆ if let

if let은 match 와 달리 하나의 패턴만 매칭시키고, 나머지 패턴은 무시하고 싶을 때 주로 사용됩니다.

#[derive(Debug)]
enum Info{
    Name(String),
    Age(u32),
}

fn show_name(info : Info) -> String {
    if let Info::Name(name) = info{
        name
    }else{
        String::from("Something")
    }
}

fn main(){
    // if let 조건 예시 데이터 셋팅
    let s = show_name(Info::Name(String::from("Hyunmin Han")));
    println!("Name : {}", s);

    // else 조건 예시 데이터 셋팅
    let s = show_name(Info::Age(29));
    println!("Name : {}", s);
}

▶ 출력 결과

Name : Hyunmin Han
Name : Something
반응형
반응형

■ 열거형

열거형은 하나의 타입이 가질 수 있는 값들을 다양하게 열거함으로써 타입을 정의할 수 있습니다. 열거형의 항목은 다양한 타입으로 설정할 수 있으며, 열거형은 구조체와 같이 메소드와 연관함수를 구현할 수 있습니다.


◆ 다양한 타입으로 설정

Info 열거형의 항목을 다양하게 String, u32, 구조체, 열거형으로 정의함으로써 열거형의 특징을 확인할 수 있습니다.

#[derive(Debug)]
enum Gender{
    Male,
    Female,
}

#[derive(Debug)]
enum Info{
    // String 타입
    Name(String),
    // u32 타입
    Age(u32),
    // 구조체
    Location{x : i32, y : i32},
    // 열거형
    Gender(Gender)
}
fn main(){
    let name = Info::Name(String::from("Hyunmin han"));
    let age = Info::Age(29);
    let location = Info::Location{ x : 132, y : 80};
    let gender = Info::Gender(Gender::Male);
    
    println!("Name : {:?}", name);
    println!("Age : {:?}", age);
    println!("Location : {:?}", location);
    println!("Gender : {:?}", gender);
}

▶ 출력 결과

Name : Name("Hyunmin han")
Age : Age(29)
Location : Location { x: 132, y: 80 }
Gender : Gender(Male)

◆ 메소드와 연관함수 활용

Info 열거형의 impl(구현부)를 통해 show 메소드와 new_name 연관함수를 구현함으로써, 열거형의 메소드와 연관함수 활용법을 확인할 수 있습니다.

#[derive(Debug)]
enum Info{
    Name(String),
}

impl Info{
    // 메소드 정의
    fn show(&self){
        println!("{:?}", self);
    }

    // 연관 함수 정의
    fn new_name(s : String) -> Info {
        Info::Name(s)
    }
}
fn main(){
    // 연관 함수 호출
    let name  = Info::new_name(String::from("Hyunmin han"));

    // 메소드 호출
    name.show();
}

▶ 출력 결과

Name("Hyunmin han")
반응형
반응형

■ 구조체의 메소드

구조체의 메소드는 구조체의 impl 블록에서 정의해야 하며 메소드의 첫번째 파라미터는 self가 됩니다. 추가적으로 impl의 명은 구조체의 명과 동일해야 하며, 첫번째 파라미터 self는 메소드를 호출하는 인스턴스를 가르킵니다.

struct Person{
    name : String,
    age : u32,
    address : String,
    email : String,
}

// 구조체 구현
impl Person{
    // 메소드 정의
    fn show_person(&self) {
        println!("Name : {}", self.name);
        println!("Age : {}", self.age);
        println!("Address : {}", self.address);
        println!("Email : {}", self.email);
    }
}

fn main(){
    // 인스턴스 생성
    let person = Person{
        name : String::from("Hyunmin han"),
        age : 29,
        address : String::from("서울시 강남구 역삼동"),
        email : String::from("hyunmin@gmail.com"),
    };
    
    // show_person 메소드 호출
    person.show_person();
}

▶ 출력 결과

Name : Hyunmin han
Age : 29
Address : 서울시 강남구 역삼동
Email : hyunmin@gmail.com

■ 구조체의 연관함수

구조체의 연관 함수는 메소드와 다르게 self 파라미터를 갖지 않는 함수이며 구조체::연관함수 문법을 사용하여 호출합니다.

struct Person{
    name : String,
    age : u32,
    address : String,
    email : String,
}

// 구조체 구현
impl Person{
    // 연관 함수 정의
    fn new_person(name : String, age : u32, address : String, email : String) -> Person{
        Person{
            name,
            age,
            address,
            email,
        }
    }
}

fn main(){
    // 연관 함수를 통해 새로운 인스턴스 생성
    let person = Person::new_person(
        String::from("Hyunmin han"),
        29,
        String::from("서울시 강남구 역삼동"),
        String::from("hyunmin@gmail.com"),
    );

    println!("Name : {}", person.name);
    println!("Age : {}", person.age);
    println!("Address : {}", person.address);
    println!("Email : {}", person.email);
}

▶ 출력 결과

Name : Hyunmin han
Age : 29
Address : 서울시 강남구 역삼동
Email : hyunmin@gmail.com
반응형
반응형

■ 구조체

구조체는 튜플과 유사하게 구조체의 구성요소들을 각각 다른 타입으로 가질 수 있습니다.

튜플은 구성요소에 접근하기 위해 색인을 이용하지만, 구조체는 각 구성요소들을 명명함으로써 구성요소에 접근할 때 순서에 의존하지 않고 접근할 수 있습니다.


◆ 구조체 인스턴스 생성

Person 구조체를 정의하고 인스턴스를 생성하여 모든 구성요소를 출력합니다.

구조체가 구성요소에 접근할 때는 튜플과 동일하게 점(.)을 이용합니다.

struct Person{
    name : String,
    age : u32,
    address : String,
    email : String,
}

fn main(){
    // 인스턴스 생성
    let person = Person{
        name : String::from("Hyunmin han"),
        age : 29,
        address : String::from("서울시 강남구 역삼동"),
        email : String::from("hyunmin@gmail.com"),
    };
    
    // 구성요소에 접근
    println!("Name : {}", person.name);
    println!("Age : {}", person.age);
    println!("Address : {}", person.address);
    println!("Email : {}", person.email);
}

▶ 출력 결과

Name : Hyunmin han
Age : 29
Address : 서울시 강남구 역삼동
Email : hyunmin@gmail.com

◆ 구조체의 필드명과 변수명이 같을 경우 변수명으로 초기화 가능

구조체의 필드명과 변수명이 같을 때는 필드명 : 값 형식이 아닌 변수명 으로 초기화 할 수 있습니다.

struct Person{
    name : String,
    age : u32,
    address : String,
    email : String,
}

fn build_person(name : String, age : u32, address : String, email : String) -> Person{
    // 필드와 변수명이 같을 때 초기화
    Person { 
        name, 
        age, 
        address, 
        email 
    }
}

fn main(){
    let person = build_person(
        String::from("Hyunmin han"),
        29,
        String::from("서울시 강남구 역삼동"),
        String::from("hyunmin@gmail.com")
    );

    println!("Name : {}", person.name);
    println!("Age : {}", person.age);
    println!("Address : {}", person.address);
    println!("Email : {}", person.email);
}

▶ 출력 결과

Name : Hyunmin han
Age : 29
Address : 서울시 강남구 역삼동
Email : hyunmin@gmail.com

◆ 구조체의 갱신

A 인스턴스를 활용하여 B 인스턴스를 생성할 때 A 인스턴스의 필드를 그대로 사용해야 할 경우 구조체의 갱신법을 사용할 수 있습니다.

struct Person{
    name : String,
    age : u32,
    address : String,
    email : String,
}

fn main(){
    let person1 = Person{
        name : String::from("Hyunmin han"),
        age : 29,
        address : String::from("서울시 강남구 역삼동"),
        email : String::from("hyunmin@gmail.com"),
    };

    let person2 = Person{
        name : String::from("Donghun lee"),
        age : 28,
        // person1의 address, email 필드를 그대로 가져와서 사용
        ..person1
    };

    println!("Name : {}", person2.name);
    println!("Age : {}", person2.age);
    println!("Address : {}", person2.address);
    println!("Email : {}", person2.email);
}

▶ 출력 결과

Name : Donghun lee
Age : 28
Address : 서울시 강남구 역삼동
Email : hyunmin@gmail.com

◆ 튜플 구조체

구조체에 필드명을 명명하지 않고 타입만을 정의하여 사용합니다.

튜플의 데이터 접근 방식과 동일하게 색인(인덱스)으로 데이터에 접근합니다.

struct Location(i32, i32, i32);

fn main(){
    let top = Location(100, 100, 100);
    let bottom = Location(0, 0, 0);

    println!("Top : X : {}, Y :{}, Z :{}", top.0, top.1, top.2);
    println!("Bottom : X : {}, Y :{}, Z :{}", bottom.0, bottom.1, bottom.2);
}

▶ 출력 결과

Top : X : 100, Y :100, Z :100
Bottom : X : 0, Y :0, Z :0
반응형

+ Recent posts