Table of Contents
Rust – 시작하기
Hello World
fn main() {
println!("Hello, world!");
}
변수
변수의 불변성
변수는 디폴트로 불변이다.(immutable)
가변변수로 만들려면 mut 를 붙여야 한다.(mutable)
fn main() {
let i = 10;
let j : i32 = 20;
let mut k = 30;
println!("k = {}", k);
k = 40;
println!("i = {}, j = {}, k = {}", i, j, k);
}
tuple
fn main() {
let (i, j) = (10, 20);
println!("i * j = {}", i * j);
}
배열(array)
fn main() {
let lst = [1, 2, 3];
println!("size = {}, first = {}", lst.len(), lst[0]);
for i in lst {
println!("{}", i);
}
}
String
fn main() {
let mut s = String::new();
s.push_str("hello");
s.push_str(", world!");
println!("{}", s);
let mut s = String::from("hello");
s.push_str(", world!");
println!("{}", s);
}
캐스팅
fn main() {
let decimal = 65.4321_f32;
// Explicit conversion
let integer = decimal as u8;
let character = integer as char;
println!("{}, {}, {}", decimal, integer, character)
}
제어문
if
fn main() {
let i = 10;
if i <= 5 {
println!("i 는 5 이하이다.");
} else if i <= 10 {
println!("i 는 10 이하이다.");
} else {
println!("i 는 10 보다 크다.");
}
}
fn main() {
let i = 10;
let j = if i != 5 {
5
} else {
6
};
println!("j = {}", j);
}
loop, while, for
fn main() {
let mut i = 1;
loop {
println!("i = {}", i);
if i >= 10 {
break;
} else {
i = i + 1;
}
}
}
fn main() {
let mut i = 1;
while i <= 10 {
println!("i = {}", i);
i = i + 1;
}
}
fn main() {
for i in 1..11 {
println!("i = {}", i);
}
}
switch(X), match(O)
rust 에서는 switch 보다 더 강력한 match 를 제공한다.
use std::cmp::Ordering;
fn main() {
let i = 10;
let j = 20;
match i.cmp(&j) {
Ordering::Less => println!("작습니다."),
Ordering::Greater => println!("큽니다."),
Ordering::Equal => {
println!("OK!");
},
}
}
함수
기초
fn main() {
println!("메인 함수");
sub_function();
}
fn sub_function() {
println!("서브 함수");
}
파라미터 전달
fn main() {
sub_function(5, 6);
}
fn sub_function(x: i32, y: i32) {
println!("{} * {} = {}", x, y, x * y);
}
리턴값
return 키워드를 사용할 수도 있고, 아래처럼 마지막 라인에 표현식을 리턴값으로 쓸 수도 있다.
표현식을 리턴값으로 쓸 때는 세미콜론(;)을 생략해야 한다.
fn main() {
println!("5 * 6 = {}", sub_function(5, 6));
}
fn sub_function(x: i32, y: i32) -> i32 {
x * y
}
소유권(Ownership)
rust 의 핵심 기능이 바로 소유권이다.
소유권 규칙
- 각각의 값은 해당 값의 오너(owner)라고 불리우는 하나의 변수를 갖는다.
- 한번에 딱 하나의 오너만 존재할 수 있다.
- 오너가 스코프 밖으로 벗어나는 때, 값은 버려진다(dropped).
딱 하나의 오너(소유권 이전)
소유권이 이전되면 이전 변수는 더이상 사용할 수 없다.
소유권 이전 방식은 변수입력, 함수 파라미터 전달, 함수 리턴값의 방식이 있다.
fn main() {
let s1 = String::from("hello");
let s2 = s1;
println!("{}, world!", s2); // ok
// println!("{}, world!", s1); // error
}
복사
fn main() {
let s1 = String::from("hello");
let s2 = s1.clone();
println!("{}, world!", s2); // ok
println!("{}, world!", s1); // ok
}
포인터(X), 참조자(O)
rust 는 관리하기 힘든 포인터를 대신해서, 참조자를 이용한다.
참조자는 소유권 이전이 없다
참조자(&) 를 이용해 소유권 이전없이 값을 전달할 수 있다.
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize {
s.len()
}
가변 참조자(Mutable References)
참조자 역시 불변이 디폴트이다.
변경 가능한 참조자를 이용하려면 &mut
를 붙여야 한다.
fn main() {
let mut s = String::from("hello");
change(&mut s);
println!("{}", s)
}
fn change(some_string: &mut String) {
some_string.push_str(", world");
}
참조자의 규칙
둘 중 한가지의 참조자만 가질 수 있다.
- 가변 참조자 단 한개
- 여러 개의 불변 참조자
슬라이스(Slices)
컬렉션의 일부에 대한 참조를 슬라이스라고 한다.
TODO
구조체
기본
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
필드 순서는 달라도 상관없다.
let mut user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
user1.email = String::from("skyer9@gmail.com");
println!("{}", user1.username);
기존 구조체의 값을 이용해 새 구조체를 생성할 수 있다.
let user2 = User {
username: String::from("anotherusername567"),
..user1
};
tuple 구조체
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
모듈
main.rs
pub mod file1;
fn main() {
file1::func("Lee");
}
file1.rs
pub fn func(name: &str) {
println!("Hello {}", name.to_string());
}
메모리 관리
Box<T>
- 컴파일 타임에 크기를 알 수 없는 타입을 저장할 수 있다.
- 커다란 데이타의 소유권 이전시 복사가 발생하지 않는다.
generic
기본
fn show<T>(x: T) -> T {
x
}
fn main() {
println!("{}", show(10.0));
}
struct Point<T, U> {
x: T,
y: U,
}
fn main() {
let p = Point {
x: 1, y: 2.0
};
println!("{}, {}", p.x, p.y);
}
에러가 발생한다.
트레잇(trait) 에서 에러를 방지하는 방법을 설명한다.
// error
fn multiply<T>(x: T, y: T) -> T {
x * y
}
트레잇(trait)
구조체와 트레잇(trait)
Java interface 와 유사하다.
trait Animal {
fn custom_bark(&self);
fn common_bark(&self) {
println!("Common Bark");
}
}
struct Dog {
pomeranian : String,
poodle : String,
dashs_hund : String,
}
impl Animal for Dog {
fn custom_bark(&self) {
println!("Pomeranian Bark : {}", self.pomeranian);
println!("Poodle Bark : {}", self.poodle);
println!("Dashshund Bark : {}", self.dashs_hund);
}
}
fn main() {
let dog = Dog{
pomeranian : String::from("낑낑"),
poodle : String::from("멍멍"),
dashs_hund : String::from("댕댕")
};
dog.common_bark();
dog.custom_bark();
}
generic 과 트레잇(trait)
trait Animal {
fn custom_bark(&self);
fn common_bark(&self) {
println!("Common Bark");
}
}
struct Dog {
pomeranian : String,
poodle : String,
dashs_hund : String,
}
struct Cat {
ragdoll: String,
russian_blue: String,
manx: String,
}
impl Animal for Dog {
fn custom_bark(&self) {
println!("Pomeranian Bark : {}", self.pomeranian);
println!("Poodle Bark : {}", self.poodle);
println!("Dashshund Bark : {}", self.dashs_hund);
}
}
impl Animal for Cat {
fn custom_bark(&self) {
println!("Cat Bark");
println!("Ragdoll Bark : {}", self.ragdoll);
println!("RussianBlue Bark : {}", self.russian_blue);
println!("Manx Bark : {}", self.manx);
}
}
fn animal_bark<T : Animal>(animal : T){
animal.custom_bark();
}
fn main() {
let dog = Dog{
pomeranian : String::from("낑낑"),
poodle : String::from("멍멍"),
dashs_hund : String::from("댕댕")
};
let cat = Cat{
ragdoll: String::from("냐옹"),
russian_blue: String::from("캬악"),
manx: String::from("꾹꾹")
};
animal_bark(dog);
animal_bark(cat);
}
generic 과 트레잇(trait) 여러개
여러개의 트레잇을 받으려면 아래처럼 +
로 추가할 수 있다.
fn some_function<T: Display + Clone, U: Clone + Debug>(t: T, u: U) -> i32 {
// ......
}
트레잇을 where
쪽으로 옮길 수 있다.
fn some_function<T, U>(t: T, u: U) -> i32
where T: Display + Clone,
U: Clone + Debug
{
// ......
}
multiply() 오류 수정
use std::ops::Mul;
fn multiply<T: Mul<Output=T>>(x: T, y: T) -> T {
x * y
}
fn main() {
println!("{}", multiply(5, 6));
}
구구단
fn main() {
for i in 2..10 {
for j in 1..10 {
println!("{} x {} = {}", i, j, i * j);
}
}
}
입력받기
&mut guess
& 는 참조자이다.
참조는 디폴트로 불변이므로 mut 를 붙여야 한다.
use std::io;
use std::io::Write;
fn main() {
print!("숫자를 입력하세요[1-100]: ");
io::stdout().flush().unwrap();
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("잘못된 값입니다.");
println!("입력값: {}", guess);
}
랜덤 숫자 생성
Cargo.toml
[dependencies]
rand = "0.8.5"
extern crate rand;
use std::io;
use std::io::Write;
use std::cmp::Ordering;
use rand::Rng;
fn main() {
println!("숫자 맞추기!");
let secret_number = rand::thread_rng().gen_range(1..101);
print!("생각하는 숫자를 입력하세요[1-100]: ");
io::stdout().flush().unwrap();
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("잘못된 값입니다.");
let guess: u32 = guess.trim().parse()
.expect("숫자가 아닙니다.");
println!("랜덤값: {}", secret_number);
println!("입력값: {}", guess);
match guess.cmp(&secret_number) {
Ordering::Less => println!("너무 작습니다."),
Ordering::Greater => println!("너무 큽니다."),
Ordering::Equal => println!("빙고!"),
}
}
숫자 맞추기
extern crate rand;
use std::io;
use std::io::Write;
use std::cmp::Ordering;
use rand::Rng;
fn main() {
println!("숫자 맞추기!");
let secret_number = rand::thread_rng().gen_range(1..101);
loop {
print!("생각하는 숫자를 입력하세요[1-100]: ");
io::stdout().flush().unwrap();
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("잘못된 값입니다.");
let guess: u32 = guess.trim().parse()
.expect("숫자가 아닙니다.");
match guess.cmp(&secret_number) {
Ordering::Less => println!("너무 작습니다."),
Ordering::Greater => println!("너무 큽니다."),
Ordering::Equal => {
println!("빙고!");
break;
},
}
}
}