[0x03] Using Structs to Structure Related Data
struct
키워드를 이용해서 구조체를 만들 수 있다.
1. Defining and Instantiating Structs
1.1 Structure
tuple
과 다르게 각 필드
에 대해 이름을 붙일 수 있다.
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
- 구조체를 만든 다음에는
key : value
구조로 instance
를 만들어서 사용할 수 있다.
- 인스턴스를 만들 때, 필드의 순서를 바꿔서 적을 수도 있다.
fn main() {
let user1 = User {
email: String::from("[email protected]"),
username: String::from("someone"),
active: true,
sign_in_count: 1,
};
}
- 구조체에서
.
을 이용해 특정 값을 얻어올 수 있다.
- 인스턴스가
mutable
하게 선언되었다면, 값을 변경하는 것도 가능하다.
fn main() {
let mut user1 = User {
email: String::from("[email protected]"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
user1.email = String::from("[email protected]");
}
- 함수를 이용해서 변경하는 것도 가능하다.
fn build_user(email:String, username:String) -> User {
User {
email: email,
username: username,
active: true,
sign_in_count: 1,
}
}
1.1.1 Using the Field Init Shorthand
Rust
에서는 필드와 함수 인자의 이름이 같을 경우, 생략할 수 있다.
fn build_user(email: String, username: String) -> User {
User {
email,
username,
active: true,
sign_in_count: 1,
}
}
1.1.2 Creating a new Instance w/ other Instance
- 또, 다른
struct
로 부터의 값을 이용해서 새로운 인스턴스를 만들 수 있다.
fn main() {
// --skip--
let user2 = User {
active: user1.active,
username: user1.username,
email: String::from("[email protected]"),
sign_in_count: user1.sign_in_count,
};
}
Rust
에서는 이것도 줄일 수 있는 방법으로 ..
문법을 제공한다.
fn main() {
// --skip--
let user2 = User {
email: String::from("[email protected]"),
..user1
};
}
- 한 가지 주목할 점은
user2
인스턴스를 생성하며, =
연산자를 사용한 점이다.
- 이는
Ownership
에 대해 설명할 때 살펴본 move
를 했기 때문이다.
- 따라서,
user1
은 user2
를 생성한 후 소유권을 잃고 사용할 수 없게 된다.
- 구체적으로 말하면,
힙 영역
을 사용하는 데이터들(email
, username
)이 move
되어버렸기 때문이다.
- 따라서,
user2
의 username
도 따로 선언해준다면 copy
만 일어나게 되고, 결과적으로user1
도 문제 없이 사용할 수 있다.
1.2 Tuple Structure
tuple structure
에서는 각 필드에 대한 이름이 없다.
tuple
에 이름을 붙일 때 유용하게 사용할 수 있다.
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
fn main() {
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
}
black
과 origin
은 각각 서로 다른 tuple structure
의 인스턴스이므로 서로 다른 타입이다.
- 즉, 필드가 같은 형태로 구성되어 있다고 하더라도 이름이 다르면 서로 다른 타입이다.
tuple structure
는 tuple
과 마찬가지로 아래 두 가지가 가능하다.
destructuring
.
연산자로 값 참조
1.3 Unit-Like structs
- 필드가 아예 없는
structure
를 만들 수도 있다.
- 이들은
unit-like structs
라 불리고, ()
와 비슷하게 작동한다.
unit-like structs
는 trait
을 구현할 때 특히 유용하다.
- 특정
type
이 타입 자체에 저장하려는 데이터가 없을 때, ()
를 사용할 수 있다.
struct AlwaysEqual;
fn main() {
let subject = AlwaysEqual;
}
Ownership Of Struct Data
- 위에서 살펴본
User
구조체에서 &str
대신에 String
타입을 사용한 것은 Rust
의 lifetime
개념에 대한 이해가 필요하다.
2. Structs Example
- 직사각형의 넓이를 구하는 코드를 작성하며
struct
에 대한 이해를 해보자.
[1]
struct
없이, 단순한 코드를 작성한다.
fn main() {
let width1 = 30;
let height1 = 50;
println!(
"The area of the rectangle is {} square pixels.",
area(width1, height1)
);
}
fn area(width: u32, height: u32) -> u32 {
width * height
}
[2] +Tuple
tuple
을 사용하여 코드를 작성한다.
fn main() {
let rect1 = (30, 50);
println!(
"The area of the rectangle is {} square pixels.",
area(rect1)
);
}
fn area(dimensions: (u32, u32)) -> u32 {
dimensions.0 * dimensions.1
}
[3] +Structs
structs
를 사용하여 보다 의미 있는 코드를 작성한다.
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
}
println!(
"The area of the rectangle is {} square pixels.",
area(&rect1)
);
}
fn area(rectangle: &Rectangle) -> u32 { // one parameter!
rectangle.width * rectangle.height
}
[4] +Debugging
- 코딩 중에 디버깅을 하는 것이 필요한 순간이 있다.
- 이 때,
println!
을 통해 데이터 값을 체크 할 수 있는데, 이 때 Display
라는 format 을 사용한다.
td::fmt::Display
이다.
struct
의 경우에는 출력하는 포맷의 모호함
때문에 따로 Display
의 구현을 제공하지 않는다.
struct
의 내용을 출력하고 싶으면 {}
대신에 {:?}
또는 {:#?}
(for pretty-print) 를 쓰면 된다.
- 또,
struct
에 Debug
라는 trait
이 구현되어 있지 않으면 #[derive(Debug)]
를 적어주어야 한다.
#[derive(Debug)] // implements Debug trait
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let a = Rectangle{
width: 30,
height: 20,
};
println!("The info of area: {:?}", a); // formatting for structs
println!("The size of area is {}", area(a));
}
fn area(rectangle: Rectangle) -> u32 {
rectangle.width * rectangle.height
}
- 또 다른 방법은
dbg!
매크로를 사용하는 것이다.
dbg!
를 사용하면 코드 라인까지 출력해준다.
[5] misc
Rust
에서는 Debug
외에도 여러가지 trait
을 제공한다.
- 이러한
trait
들은 structs
와 같은 custom type 을 만들 때 많이 유용하다.
3. Method Syntax
method
는 함수와 비슷하지만, structs
의 컨텍스트 내부에서 정의된다.
- 또한, 첫 번째 인자로
self
를 받는다.
self
는 해당 메소드를 호출하는 structs
의 instance
를 가리킨다.
3.1 Defining Method
method
의 정의는 아래 코드를 참고하자.
#[derive(Debug)]
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!(
"The area of the rectangle is {} square pixels.",
rect1.area()
);
}
- 여기서
&self
는 사실 self:&Self
의 축약이다.
Self
는 impl
블록의 타입을 의미한다.
- 일반적으로
method
들은 self
의 소유권을 가져오는 경우가 드물기 때문에, 대부분 &self
를 사용한다.
method
를 사용하는 가장 큰 이유는 특정 타입에 대한 함수들을 한 곳에 모아두기 위함이다.
- 다른 언어들에서는 getter 라 불리는
method
를 많이 구현해준다.
- 이는, 필드 값을 read-only 로 바로 참조할 수 있도록 해주는
method
이다.
- 하지만,
Rust
에서는 이를 자동으로 구현해주지 않는다.
3.2 Methods w/ more parameters
- 예제 코드는 아래와 같다.
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
3.3 Associated Functions
- 모든
method
를 Associated Function
이라고 부를 수 있다.
self
를 첫 번째 인자로 갖지 않는, association function
을 구현하는 것이 가능하다.
- 사실
String
에서도 String::from()
에는 self
가 없다.
- 보통 이런 함수는
constructor
에 쓸 수 있다.
impl Rectangle {
fn square(size: u32) -> Rectangle {
Rectangle {
width: size,
height: size,
}
}
}
- 이러한
association function
은 ::
연산자로 호출할 수 있다.
- 예를 들어,
let sq = Rectangle::square(3)
이런 식이다.
3.4 Multiple impl Blocks
impl
블록이 하나만 있어야 한다는 법은 없다.
- 아래와 같은 코드도 유효하다.
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
impl Rectangle {
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
Author And Source
이 문제에 관하여([0x03] Using Structs to Structure Related Data), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@c0np4nn4/0x03-Using-Structs-to-Structure-Related-Data
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
tuple
과 다르게 각 필드
에 대해 이름을 붙일 수 있다.struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
key : value
구조로 instance
를 만들어서 사용할 수 있다.fn main() {
let user1 = User {
email: String::from("[email protected]"),
username: String::from("someone"),
active: true,
sign_in_count: 1,
};
}
.
을 이용해 특정 값을 얻어올 수 있다.mutable
하게 선언되었다면, 값을 변경하는 것도 가능하다.fn main() {
let mut user1 = User {
email: String::from("[email protected]"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
user1.email = String::from("[email protected]");
}
fn build_user(email:String, username:String) -> User {
User {
email: email,
username: username,
active: true,
sign_in_count: 1,
}
}
Rust
에서는 필드와 함수 인자의 이름이 같을 경우, 생략할 수 있다.fn build_user(email: String, username: String) -> User {
User {
email,
username,
active: true,
sign_in_count: 1,
}
}
struct
로 부터의 값을 이용해서 새로운 인스턴스를 만들 수 있다.fn main() {
// --skip--
let user2 = User {
active: user1.active,
username: user1.username,
email: String::from("[email protected]"),
sign_in_count: user1.sign_in_count,
};
}
Rust
에서는 이것도 줄일 수 있는 방법으로 ..
문법을 제공한다.fn main() {
// --skip--
let user2 = User {
email: String::from("[email protected]"),
..user1
};
}
user2
인스턴스를 생성하며, =
연산자를 사용한 점이다.Ownership
에 대해 설명할 때 살펴본 move
를 했기 때문이다.user1
은 user2
를 생성한 후 소유권을 잃고 사용할 수 없게 된다.힙 영역
을 사용하는 데이터들(email
, username
)이 move
되어버렸기 때문이다.user2
의 username
도 따로 선언해준다면 copy
만 일어나게 되고, 결과적으로user1
도 문제 없이 사용할 수 있다.tuple structure
에서는 각 필드에 대한 이름이 없다.tuple
에 이름을 붙일 때 유용하게 사용할 수 있다.struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
fn main() {
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
}
black
과 origin
은 각각 서로 다른 tuple structure
의 인스턴스이므로 서로 다른 타입이다.tuple structure
는 tuple
과 마찬가지로 아래 두 가지가 가능하다.destructuring
.
연산자로 값 참조
structure
를 만들 수도 있다.unit-like structs
라 불리고, ()
와 비슷하게 작동한다.unit-like structs
는 trait
을 구현할 때 특히 유용하다.- 특정
type
이 타입 자체에 저장하려는 데이터가 없을 때,()
를 사용할 수 있다.
struct AlwaysEqual;
fn main() {
let subject = AlwaysEqual;
}
Ownership Of Struct Data
- 위에서 살펴본
User
구조체에서&str
대신에String
타입을 사용한 것은Rust
의lifetime
개념에 대한 이해가 필요하다.
- 직사각형의 넓이를 구하는 코드를 작성하며
struct
에 대한 이해를 해보자.
[1]
struct
없이, 단순한 코드를 작성한다.
fn main() {
let width1 = 30;
let height1 = 50;
println!(
"The area of the rectangle is {} square pixels.",
area(width1, height1)
);
}
fn area(width: u32, height: u32) -> u32 {
width * height
}
[2] +Tuple
tuple
을 사용하여 코드를 작성한다.
fn main() {
let rect1 = (30, 50);
println!(
"The area of the rectangle is {} square pixels.",
area(rect1)
);
}
fn area(dimensions: (u32, u32)) -> u32 {
dimensions.0 * dimensions.1
}
[3] +Structs
structs
를 사용하여 보다 의미 있는 코드를 작성한다.
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
}
println!(
"The area of the rectangle is {} square pixels.",
area(&rect1)
);
}
fn area(rectangle: &Rectangle) -> u32 { // one parameter!
rectangle.width * rectangle.height
}
[4] +Debugging
- 코딩 중에 디버깅을 하는 것이 필요한 순간이 있다.
- 이 때,
println!
을 통해 데이터 값을 체크 할 수 있는데, 이 때Display
라는 format 을 사용한다. td::fmt::Display
이다.
struct
의 경우에는 출력하는 포맷의모호함
때문에 따로Display
의 구현을 제공하지 않는다.struct
의 내용을 출력하고 싶으면{}
대신에{:?}
또는{:#?}
(for pretty-print) 를 쓰면 된다.- 또,
struct
에Debug
라는trait
이 구현되어 있지 않으면#[derive(Debug)]
를 적어주어야 한다.
#[derive(Debug)] // implements Debug trait
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let a = Rectangle{
width: 30,
height: 20,
};
println!("The info of area: {:?}", a); // formatting for structs
println!("The size of area is {}", area(a));
}
fn area(rectangle: Rectangle) -> u32 {
rectangle.width * rectangle.height
}
- 또 다른 방법은
dbg!
매크로를 사용하는 것이다. dbg!
를 사용하면 코드 라인까지 출력해준다.
[5] misc
Rust
에서는Debug
외에도 여러가지trait
을 제공한다.- 이러한
trait
들은structs
와 같은 custom type 을 만들 때 많이 유용하다.
3. Method Syntax
method
는 함수와 비슷하지만, structs
의 컨텍스트 내부에서 정의된다.
- 또한, 첫 번째 인자로
self
를 받는다.
self
는 해당 메소드를 호출하는 structs
의 instance
를 가리킨다.
3.1 Defining Method
method
의 정의는 아래 코드를 참고하자.
#[derive(Debug)]
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!(
"The area of the rectangle is {} square pixels.",
rect1.area()
);
}
- 여기서
&self
는 사실 self:&Self
의 축약이다.
Self
는 impl
블록의 타입을 의미한다.
- 일반적으로
method
들은 self
의 소유권을 가져오는 경우가 드물기 때문에, 대부분 &self
를 사용한다.
method
를 사용하는 가장 큰 이유는 특정 타입에 대한 함수들을 한 곳에 모아두기 위함이다.
- 다른 언어들에서는 getter 라 불리는
method
를 많이 구현해준다.
- 이는, 필드 값을 read-only 로 바로 참조할 수 있도록 해주는
method
이다.
- 하지만,
Rust
에서는 이를 자동으로 구현해주지 않는다.
3.2 Methods w/ more parameters
- 예제 코드는 아래와 같다.
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
3.3 Associated Functions
- 모든
method
를 Associated Function
이라고 부를 수 있다.
self
를 첫 번째 인자로 갖지 않는, association function
을 구현하는 것이 가능하다.
- 사실
String
에서도 String::from()
에는 self
가 없다.
- 보통 이런 함수는
constructor
에 쓸 수 있다.
impl Rectangle {
fn square(size: u32) -> Rectangle {
Rectangle {
width: size,
height: size,
}
}
}
- 이러한
association function
은 ::
연산자로 호출할 수 있다.
- 예를 들어,
let sq = Rectangle::square(3)
이런 식이다.
3.4 Multiple impl Blocks
impl
블록이 하나만 있어야 한다는 법은 없다.
- 아래와 같은 코드도 유효하다.
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
impl Rectangle {
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
Author And Source
이 문제에 관하여([0x03] Using Structs to Structure Related Data), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@c0np4nn4/0x03-Using-Structs-to-Structure-Related-Data
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
method
는 함수와 비슷하지만, structs
의 컨텍스트 내부에서 정의된다.self
를 받는다.self
는 해당 메소드를 호출하는 structs
의 instance
를 가리킨다.method
의 정의는 아래 코드를 참고하자.#[derive(Debug)]
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!(
"The area of the rectangle is {} square pixels.",
rect1.area()
);
}
&self
는 사실 self:&Self
의 축약이다.Self
는 impl
블록의 타입을 의미한다.method
들은 self
의 소유권을 가져오는 경우가 드물기 때문에, 대부분 &self
를 사용한다.method
를 사용하는 가장 큰 이유는 특정 타입에 대한 함수들을 한 곳에 모아두기 위함이다.method
를 많이 구현해준다.method
이다.Rust
에서는 이를 자동으로 구현해주지 않는다.impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
method
를 Associated Function
이라고 부를 수 있다.self
를 첫 번째 인자로 갖지 않는, association function
을 구현하는 것이 가능하다.String
에서도 String::from()
에는 self
가 없다.constructor
에 쓸 수 있다.impl Rectangle {
fn square(size: u32) -> Rectangle {
Rectangle {
width: size,
height: size,
}
}
}
association function
은 ::
연산자로 호출할 수 있다.let sq = Rectangle::square(3)
이런 식이다.impl
블록이 하나만 있어야 한다는 법은 없다.impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
impl Rectangle {
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
Author And Source
이 문제에 관하여([0x03] Using Structs to Structure Related Data), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@c0np4nn4/0x03-Using-Structs-to-Structure-Related-Data저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)