수색…


통사론

  • struct Foo {field1 : Type1, field2 : Type2}
  • let foo = Foo {field1 : Type1 :: new (), field2 : Type2 :: new ()};
  • 구조체 바 (Type1, Type2); // 튜플 유형
  • let = = Bar (Type1 :: new (), Type2 :: new ());
  • Baz 구조체; // 단위 같은 유형
  • 하자 _ = Baz;
  • let Foo {field1, ..} = foo; // 패턴 매칭으로 field1 추출
  • let Foo {field1 : x, ..} = foo; // field1을 x로 추출합니다.
  • let foo2 = Foo {field1 : Type1 :: new (), .. foo}; // 기존에서 구성
  • impl Foo {fn fiddle (& self) {}} // Foo에 대한 인스턴스 메소드 선언
  • impl Foo {fn tweak (& mut self) {}} // Foo에 대한 변경 가능한 인스턴스 메소드 선언
  • impl Foo {fn double (self) {}} // Foo를위한 소유 메소드 선언
  • impl Foo {fn new () {}} // Foo 관련 메소드 선언

구조 정의

Rust의 structstruct 키워드를 사용하여 정의됩니다. 가장 일반적인 구조는 다음과 같은 일련의 필드로 구성됩니다.

struct Foo {
    my_bool: bool,
    my_num: isize,
    my_string: String,
}

위 코드는 bool , isizeString 유형의 my_bool , my_nummy_string 세 필드가있는 struct 를 각각 선언합니다.

Rust에서 struct 를 만드는 또 다른 방법은 튜플 구조체 를 만드는 것입니다.

struct Bar (bool, isize, String);

이것은 bool , isizeString 유형의 3 개의 이름없는 필드 isize 순서대로있는 새로운 유형의 Bar 정의합니다. 이는 newtype 패턴 으로 알려져 있습니다. 특정 유형에 대해 새로운 "이름"을 효과적으로 도입하기 때문입니다. 그러나 type 키워드를 사용하여 만든 별칭보다 훨씬 강력합니다. Bar 는 여기에 완전한 기능을하는 유형입니다. 즉, 자신 만의 방법을 작성할 수 있습니다 (아래).

마지막으로, 유닛과 같은 struct 라는 필드가 없는 struct 를 선언합니다.

struct Baz;

이는 조롱이나 테스트 (특성을 쉽게 구현하려는 경우) 또는 마커 유형으로 유용 할 수 있습니다. 그러나 일반적으로 많은 유닛과 같은 구조체를 접할 가능성은 거의 없습니다.

Rust의 struct 필드는 기본적으로 모두 private입니다. 즉, 형식을 정의하는 모듈 외부의 코드에서 액세스 할 수 없습니다. 해당 필드에 공개적으로 액세스 할 수 있도록 pub 키워드가있는 필드의 접두어를 붙일 수 있습니다. 또한 struct 유형 자체 는 private입니다. 다른 모듈에서 사용할 수 있도록하려면 struct 정의 앞에 pub 접두사가 있어야합니다.

pub struct X {
    my_field: bool,
    pub our_field: bool,
}

구조 값 생성 및 사용

다음 struct 정의를 고려하십시오.

struct Foo {
    my_bool: bool,
    my_num: isize,
    my_string: String,
}
struct Bar (bool, isize, String);
struct Baz;

이러한 유형에 대한 새로운 구조 값을 만드는 것은 간단합니다.

let foo = Foo { my_bool: true, my_num: 42, my_string: String::from("hello") };
let bar = Bar(true, 42, String::from("hello"));
let baz = Baz;

구조체의 필드를 사용하여 액세스하십시오 . :

assert_eq!(foo.my_bool, true);
assert_eq!(bar.0, true); // tuple structs act like tuples

구조체에 대한 변경 가능한 바인딩의 필드는 변형 될 수 있습니다.

let mut foo = foo;
foo.my_bool = false;
let mut bar = bar;
bar.0 = false;

Rust의 패턴 일치 기능을 사용하여 struct 내부를 들여다 볼 수도 있습니다.

// creates bindings mb, mn, ms with values of corresponding fields in foo
let Foo { my_bool: mb, my_num: mn, my_string: ms } = foo;
assert_eq!(mn, 42);
// .. allows you to skip fields you do not care about
let Foo { my_num: mn, .. } = foo;
assert_eq!(mn, 42);
// leave out `: variable` to bind a variable by its field name
let Foo { my_num, .. } = foo;
assert_eq!(my_num, 42);

또는 Rust의 업데이트 구문을 사용하여 두 번째 구조체를 "템플릿"으로 사용하여 구조체를 만듭니다.

let foo2 = Foo { my_string: String::from("world"), .. foo };
assert_eq!(foo2.my_num, 42);

구조체 메소드

구조체에 대한 메소드를 선언하려면 (즉, struct 또는 struct 유형의 값으로 "호출"할 수있는 함수) impl 블록을 작성하십시오.

impl Foo {
    fn fiddle(&self) {
        // "self" refers to the value this method is being called on
        println!("fiddling {}", self.my_string);
    }
}

// ...
foo.fiddle(); // prints "fiddling hello"

&selffiddle 메소드를 호출하기 위해 struct Foo 의 인스턴스에 대한 불변의 참조를 나타냅니다. 인스턴스를 수정하고 싶다면 (예 : 필드 변경), 대신 &mut self 를 취할 것입니다 (예 : 변경 가능한 참조).

impl Foo {
    fn tweak(&mut self, n: isize) {
        self.my_num = n;
    }
}

// ...
foo.tweak(43);
assert_eq!(foo.my_num, 43);

마지막으로, 우리는 또한 사용할 수 self (AN의 부족주의 & 같은 수신기)를. 인스턴스를 호출자가 소유해야하며 메소드를 호출 할 때 인스턴스가 이동하게됩니다. 기존 인스턴스를 소비, 파기 또는 완전히 변형하려는 경우 유용 할 수 있습니다. 그러한 유스 케이스의 한 예는 "연결"메소드를 제공하는 것이다.

impl Foo {
    fn double(mut self) -> Self {
        self.my_num *= 2;
        self
    }
}

// ...
foo.my_num = 1;
assert_eq!(foo.double().double().my_num, 4);

우리는 selfmut 접두사로 붙였습니다. 그래서 다시 돌려 보내기 전에 self를 mutate 할 수 있습니다. double 메서드의 반환 유형도 일부 설명을 보증합니다. impl 블록 안에있는 Selfimpl 적용되는 타입을 가리킨다 (이 경우, Foo ). 여기서는 유형의 서명을 다시 타이핑하는 것을 피하기위한 대개 유용한 속기이지만 특성에서는 특정 특성을 구현하는 기본 유형을 참조하는 데 사용할 수 있습니다.

struct 대한 관련 메소드 (일반적으로 다른 언어에서 "클래스 메소드"라고 함)를 선언하려면 self 인수를 생략하십시오. 이러한 메소드는 인스턴스 유형이 아니라 struct 유형 자체에서 호출됩니다.

impl Foo {
    fn new(b: bool, n: isize, s: String) -> Foo {
        Foo { my_bool: b, my_num: n, my_string: s }
    }
}

// ...
// :: is used to access associated members of the type
let x = Foo::new(false, 0, String::from("nil"));
assert_eq!(x.my_num, 0);

구조체 메서드는 현재 모듈에서 선언 된 형식에 대해서만 정의 할 수 있습니다. 또한 필드와 마찬가지로 모든 구조체 메서드는 기본적으로 private이므로 동일한 모듈의 코드에서만 호출 할 수 있습니다. 정의에 pub 키워드를 접두어로 붙이면 다른 곳에서 호출 할 수 있습니다.

일반 구조

구조는 하나 이상의 유형 매개 변수에 대해 일반화 할 수 있습니다. 이러한 유형은 유형을 참조 할 때 <> 묶습니다.

struct Gen<T> {
    x: T,
    z: isize,
}

// ...
let _: Gen<bool> = Gen{x: true, z: 1};
let _: Gen<isize> = Gen{x: 42, z: 2};
let _: Gen<String> = Gen{x: String::from("hello"), z: 3};

쉼표를 사용하여 여러 유형을 지정할 수 있습니다.

struct Gen2<T, U> {
    x: T,
    y: U,
}

// ...
let _: Gen2<bool, isize> = Gen2{x: true, y: 42};

유형 매개 변수는 유형의 일부이므로 같은 기본 유형이지만 매개 변수가 다른 두 변수는 서로 바꿔 쓸 수 없습니다.

let mut a: Gen<bool> = Gen{x: true, z: 1};
let b: Gen<isize> = Gen{x: 42, z: 2};
a = b; // this will not work, types are not the same
a.x = 42; // this will not work, the type of .x in a is bool

형식 매개 변수 할당에 관계없이 struct 를 받아들이는 함수를 작성하려면 해당 함수를 일반화해야합니다.

fn hello<T>(g: Gen<T>) {
    println!("{}", g.z); // valid, since g.z is always an isize
}

하지만 항상 gx 인쇄 할 수있는 함수를 작성하고 싶다면 어떻게해야할까요? T 를 표시 할 수있는 유형으로 제한해야합니다. 우리는 타입 경계를 가지고 이것을 할 수 있습니다 :

use std::fmt;
fn hello<T: fmt::Display>(g: Gen<T>) {
    println!("{} {}", g.x, g.z);
}

hello 함수는 이제 T 타입이 fmt::Display 구현하는 Gen 인스턴스에 대해서만 정의됩니다. 예를 들어 Gen<(bool, isize)> 를 전달하려고하면 컴파일러는 hello 가 해당 유형에 정의되어 있지 않다는 불평을합니다.

또한 struct 의 형식 매개 변수에 직접 형식 경계를 사용하여 특정 형식에 대해서만 struct 를 구성 할 수 있음을 나타낼 수 있습니다.

use std::hash::Hash;
struct GenB<T: Hash> {
    x: T,
}

GenB 접근 할 수있는 모든 함수는 x 의 타입이 Hash 구현하고 있다는 것을 알고 있으므로 .x.hash() 호출 할 수 있습니다. 동일한 매개 변수에 대한 여러 유형 경계는 + 로 구분하여 지정할 수 있습니다.

함수의 경우와 마찬가지로 where <> 키워드를 사용하여 <> 뒤에 유형 경계를 지정할 수 있습니다.

struct GenB<T> where T: Hash {
    x: T,
}

이는 의미 론적 의미가 동일하지만 복잡한 경계가있을 때 서명을 더 쉽게 읽고 형식을 지정할 수 있습니다.

형식 매개 변수는 인스턴스 메서드 및 관련 struct 메서드에서도 사용할 수 있습니다.

// note the <T> parameter for the impl as well
// this is necessary to say that all the following methods only
// exist within the context of those type parameter assignments
impl<T> Gen<T> {
    fn inner(self) -> T {
        self.x
    }
    fn new(x: T) -> Gen<T> {
        Gen{x: x}
    }
}

GenT 에 타입 경계가 있다면 그것들은 또한 impl 의 타입 경계에 반영되어야합니다. 또한 해당 유형이 특정 속성을 충족시키는 경우에만 주어진 메서드가 존재한다고 말하기 위해 impl 경계를 더 엄격하게 만들 수 있습니다.

impl<T: Hash + fmt::Display> Gen<T> {
    fn show(&self) {
        println!("{}", self.x);
    }
}

// ...
Gen{x: 42}.show(); // works fine
let a = Gen{x: (42, true)}; // ok, because (isize, bool): Hash
a.show(); // error: (isize, bool) does not implement fmt::Display


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow