English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Rust 구조체

Rust에서 구조체(Struct)와 튜플(Tuple)은 여러 개의 데이터를 일정하지 않은 타입으로 묶어서 전체로 형성할 수 있습니다. 그러나 구조체의 각 구성원과 그 자체에는 이름이 있어, 구성원에 접근할 때 인덱스를 기억하지 않아도 됩니다. 튜플은 정의되지 않은 다중 값 전달에 사용되며, 구조체는 일반적인 데이터 구조를 정의하는 데 사용됩니다. 구조체의 각 구성원은 '필드'라고 합니다。

구조체 정의

이것은 구조체 정의입니다:

struct Site {
    domain: String,
    name: String,
    nation: String,
    found: u32
}

주의하세요: C를 자주 사용하는 경우/C++Rust에서 struct 문은 정의에만 사용되며, 예제를 선언할 수 없습니다. 마지막에는 ; 기호가 필요하지 않으며, 각 필드 정의 후에는 , 기호로 구분합니다。

구조체 예제

Rust는 JavaScript의 많은 영향을 받았으며, 구조체를 구현할 때 JSON 객체의 key: value 문법을 사용하여 정의됩니다:

let w3codebox = Site {
    domain: String::from("ko.oldtoolbag.com)),
    name: String::from("w3codebox)),
    nation: String::from("China"),
    found: 2013
};

만약 JSON 객체에 대해 모르는 경우, 그냥 형식을 기억하면 됩니다:

구조체 클래스 이름 {
    필드 이름 : 필드 값,
    ...
}

이렇게하면 프로그램이 더 직관적이며, 정의된 순서에 따라 멤버 값을 입력할 필요가 없습니다.

如果正在示例化的结构体有字段名称和现存变量名称一样的,可以简化书写:

let domain = String::from("ko.oldtoolbag.com");
let name = String::from("w3codebox");
let w3codebox = Site {
    domain,  // 等同于 domain : domain,
    name,    // 等同于 name : name,
    nation: String::from("China"),
    traffic: 2013
};

이렇게了一种情况:你想要新建一个结构体的示例,其中大部分属性需要被设置成与现存的一个结构体属性一样,仅需更改其中的一两个字段的值,可以使用结构体更新语法:

let site = Site {
    domain: String::from("ko.oldtoolbag.com)),
    name: String::from("w3codebox)),
    ..w3codebox
};

주의: ..w3codebox 뒤에는 쉼표가 없을 수 없습니다. 이 문법은 다른 구조체 예제를 일관되게 복사하지 않게 하며, 이는 다른 예제의 값을 참조하려면 적어도 하나의 필드 값을 재설정해야 한다는 의미입니다.

튜플 구조체

구조체를 정의하고 사용하는 더 간단한 방법이 있습니다:튜플 구조체.

튜플 구조체는 형식이 튜플인 구조체입니다.

차이점은 이름과 고정된 형식의 타입 포맷이 있습니다. 존재하는 의미는 타입을 정의할 필요가 있지만 복잡하지 않은 간단한 데이터를 처리하기 위해 있습니다:

struct Color(u8, u8, u8);
struct Point(f64, f64);
let black = Color(0, 0, 0);
let origin = Point(0.0, 0.0);

"颜色"과 "점 좌표"는 일반적으로 사용되는 두 가지 데이터 타입이지만, 예제화할 때 대括号을 써서 두 이름을 적어서 읽기 쉽게 하기 위해 편리성을 희생한 경우가 있습니다. Rust는 이 문제를 유지하지 않습니다. 튜플 구조체 객체의 사용 방식은 튜플과 같으며, .과 인덱스를 통해 접근할 수 있습니다:

fn main() {
    struct Color(u8, u8, u8);
    struct Point(f64, f64);
    let black = Color(0, 0, 0);
    let origin = Point(0.0, 0.0);
    println!("black = ({}, {}, {}), black.0, black.1, black.2);
    println!("origin = ({}, {}), origin.0, origin.1);
}

실행 결과:

black = (0, 0, 0)
origin = (0, 0)

구조체 소유권

구조체는 필드 값의 소유권을 관리해야 하며, 구조체가 해제될 때 모든 필드가 해제됩니다.

따라서 이 장의 예제에서 String 타입을 사용하는 이유입니다.

하지만 구조체에서 참조형 필드를 정의하지 않는다는 것은 아닙니다. 이는 "라이프스파이크" 기계를 통해 구현되어야 합니다.

하지만 "라이프스파이크" 개념을 설명하기는 어려우며, 이는 나중 장에서 설명할 것입니다.

구조체 출력

디버깅 중에는 구조체 인스턴스를 완전히 표시하는 것이 매우 유용합니다. 하지만 수동으로 포맷을 작성하는 것은 매우 불편할 수 있습니다. 따라서 Rust는 전체 구조체를 쉽게 출력하는 방법을 제공합니다:

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}
fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };
    println!("rect1 is {:?}, rect1);
}

처음 줄과 같이: 디버깅 라이브러리를 가져오세요 #[derive(Debug)] 이후 println과 print 맥로에서 {:?}占位符를 사용하여 전체 구조체를 출력할 수 있습니다:

rect1 is Rectangle { width: 30, height: 50 }

속성이 많다면 다른占位符 {:#?}를 사용할 수 있습니다.

출력 결과:

rect1 is Rectangle {
    width: 30,
    height: 50
}

구조체 메서드

메서드(Method)와 함수(Function)은 유사하지만, 구조체 인스턴스를 처리하는 데 사용됩니다.

面向对象의 언어를 공부한 적이 있다면, 함수는 일반적으로 클래스 정의 안에 위치하며 함수에서 this를 사용하여 처리되는 인스턴스를 나타냅니다.

Rust는面向对象的 언어가 아니며, 이는 소유권 기계의 혁신에서 이해할 수 있습니다. 하지만 Rust에서는面向对象的 귀중한 아이디어를 구현할 수 있습니다.

구조체 메서드의 첫 번째 매개변수는 &self여야 하며, self는 스타일이 아니라 키워드입니다.

직사각형의 면적을 계산합니다:

struct Rectangle {
    width: u32,
    height: u32,
}
    
impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}
fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };
    println!("rect1's area is {}, rect1.area());
}

출력 결과:

rect1's area is 1500

구조체 메서드를 호출할 때 self를 입력하지 않아도 됩니다. 이는 사용의 편리성을 고려한 것입니다.

다중 매개변수의 인스턴스:

struct Rectangle {
    width: u32,
    height: u32,
}
impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
    fn wider(&self, rect: &Rectangle) -> bool {}}
        self.width > rect.width
    }
}
fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };
    let rect2 = Rectangle { width: 40, height: 20 };
    println!("{}", rect1.wider(&rect2));
}

실행 결과:

false

이 프로그램은 rect1 rect보다2 넓어요.

구조체 관련 함수

"구조체 메서드"를 "구조체 함수"라고 하지 않는 이유는 "함수"라는 이름을 이 함수에 두었기 때문입니다: 이 함수는 impl 블록에 있지만 &self 파라미터가 없습니다.

이 함수는 인스턴스에 의존하지 않지만, 사용할 때 impl 블록을 명시해야 합니다.

상속받은 String::from 함수는 "관련 함수"입니다.

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}
impl Rectangle {
    fn create(width: u32, height: u32) -> Rectangle {
        Rectangle { width, height }
    }
}
fn main() {
    let rect = Rectangle::create(30, 50);
    println!("{:?}", rect);
}

실행 결과:

Rectangle { width: 30, height: 50 }

팁:구조체 impl 블록은 몇 번 써도 그 내용을 연결하는 것과 같은 효과가 있습니다!

단위 구조체

구조체는 구성원이 없어도 단순히 상징으로 사용될 수 있습니다:

struct UnitStruct;

이러한 몸체가 없는 구조체를 단위 구조체라고 부릅니다.