์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- data communication
- Python challenge
- ์๋ฐ
- ๋ฐฑ์ค
- Rust
- ubuntu
- ๋ฌ์คํธ ํ๋ก๊ทธ๋๋ฐ ๊ณต์ ๊ฐ์ด๋
- ๋ฐ์ดํฐ ํต์
- C
- ์ด์์ฒด์
- ๋ฌ์คํธ ์์
- ๋ฌ์คํธ
- ํ์ด์ฌ ์ฒผ๋ฆฐ์ง
- Operating System
- ํ์ด์ฌ
- ์ค๋ผํด
- ์ค๋ผํดDB
- Python
- ์๋ฐ ๊ฐ๋
- java
- ํ์ด์ฌ ์๊ณ ๋ฆฌ์ฆ
- ๋ฐ์ดํฐ๋ฒ ์ด์ค
- Database
- Reversing
- ์๊ณ ๋ฆฌ์ฆ
- OS
- ํ์ด์ฌ ์ฑ๋ฆฐ์ง
- ์ฐ๋ถํฌ
- ์๋ฐ ๊ธฐ์ด
- ๋ฐฑ์ค ๋ฌ์คํธ
Archives
- Today
- Total
IT’s Portfolio
[Rust] Start Rust (Day 21) - An I/O Project: Building a Command Line Program ๋ณธ๋ฌธ
Development Study/Rust
[Rust] Start Rust (Day 21) - An I/O Project: Building a Command Line Program
f1r3_r41n 2023. 8. 24. 15:14728x90
๋ฐ์ํ
๐ฆ Rust Day 21
๐ณ๏ธ An I/O Project: Building a Command Line Program
- ๋ฌ์คํธ์ ์๋์ ์์ ์ฑ, ๋จ์ผ ๋ฐ์ด๋๋ฆฌ ์ถ๋ ฅ ๊ทธ๋ฆฌ๊ณ ๊ต์ฐจ ํ๋ซํผ ์ง์ ๋ฑ์ ํน์ง์ ๋ช ๋ น์ค ๋๊ตฌ๋ฅผ ๋ง๋๋ ๋ฐ ์ข์
grep(globally search a regular experssion and print)
1๏ธโฃ ๋ช ๋ น์ค ์ธ์ ์ฒ๋ฆฌํ๊ธฐ
- ํ๋ก์ ํธ ์ด๋ฆ :
minigrep
- ํ์ผ๋ช
๊ณผ ๊ฒ์ํ ๋ฌธ์์ด ๋ฑ ๋ ๊ฐ์ ๋ช
๋ น์ค ์ธ์๋ฅผ ์ฒ๋ฆฌ
cargo run [searchstring] [example-filename.txt]
- ํ์ผ๋ช
๊ณผ ๊ฒ์ํ ๋ฌธ์์ด ๋ฑ ๋ ๊ฐ์ ๋ช
๋ น์ค ์ธ์๋ฅผ ์ฒ๋ฆฌ
๐ค ์ธ์์ ๊ฐ ์ฝ์ด์ค๊ธฐ
std::env::args
: ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ ๊ณตํ๋ ์ ๋ฌ๋ ๋ช ๋ น์ค ์ธ์๋ฅผ ์ฝ๋ ํจ์- ๋ช
๋ น์ค ์ธ์์
๋ฐ๋ณต์(iterator)
์ ๊ณต
- ๋ช
๋ น์ค ์ธ์์
use std::env;
fn main() {
let args = env::args().collect::<Vec<String>>();
println!("{:?}", args);
}
- ์ํ๋ ํจ์๊ฐ ํ๋ ์ด์์ ๋ชจ๋์ ์ค์ฒฉ๋์์ ๋๋ ํจ์ ๋์ ๋ถ๋ชจ ๋ชจ๋์ ๋ฒ์๋ก ๊ฐ์ ธ์ค๋ ๊ฒ์ด ํธ๋ฆฌํจ
std::env::args
ํจ์๋ ์ธ์์ ์ ํจํ์ง ์์ ์ ๋์ฝ๋๊ฐ ํฌํจ๋์ด ์์ผ๋ฉด ํจ๋์ ๋ฐ์์ํดstd::env::args_os
ํจ์๋ ์ ํจํ์ง ์์ ์ ๋์ฝ๋๋ฅผ ํ์ฉํ์ง๋ง String์ด ์๋ OsString ๊ฐ์ ๋ฐ๋ณต์๋ฅผ ๋ฆฌํดํจ- OsString ๊ฐ์ ํ๋ซํผ๋ง๋ค ๋ค๋ฅด๋ฉฐ String๋ณด๋ค ํจ์ฌ ๋ณต์กํจ
Input:
cargo run
Output:
["target/debug/minigrep"]
Input:
cargo run Hi, bash!
Output:
["target/debug/minigrep", "Hi,", "bash!"]
- ๋ฒกํฐ๋ ๋ฐ์ด๋๋ฆฌ์ ์ด๋ฆ์ ์ ๋๋ก ๊ณต๋ฐฑ์ ๊ธฐ์ค์ผ๋ก ์ธ์๊ฐ ๋์ด๋์ด ์์
๐ค ์ธ์ซ๊ฐ์ ๋ณ์์ ์ ์ฅํ๊ธฐ
use std::env;
fn main() {
let args = env::args().collect::<Vec<String>>();
let q = &args[1];
let f = &args[2];
println!("๊ฒ์์ด: {q}\n๋์ ํ์ผ: {f}");
}
Input:
cargo run test sample.txt
Output:
๊ฒ์์ด: test
๋์ ํ์ผ: sample.txt
2๏ธโฃ ํ์ผ ์ฝ๊ธฐ
I'm nobody! Who are you?
Are you nobody, too?
Then there's a pair of us - don't tell!
They'd banish us, you know.
How dreary to be somebody!
How public, like a frog
To tell your name the livelong day
To an admiring bog!
- ๊ฐ์ ํ
์คํธ๊ฐ ์ฌ๋ฌ ์ค์ ๊ฑธ์ณ ๋ฐ๋ณต๋ ์์ ํฌ๊ธฐ์ ํ
์คํธ ํ์ผ
poem.txt
use std::env;
fn main() {
let args = env::args().collect::<Vec<String>>();
let q = &args[1];
let f = &args[2];
let c = std::fs::read_to_string(f).unwrap();
println!("๊ฒ์์ด: {q}\n๋์ ํ์ผ: {f}\nํ์ผ ๋ด์ฉ:\n{c}");
}
std::fs
: ํ์ผ์ ์ฒ๋ฆฌํ๋ ๋ชจ๋
3๏ธโฃ ๋ชจ๋ํ์ ์๋ฌ ์ฒ๋ฆฌ ํฅ์์ ์ํ ๋ฆฌํฉํ ๋ง
- ํจ์ ํ๋๊ฐ n ๊ฐ์ง์ ์์
์ ๋ชจ๋ ์ฒ๋ฆฌํ๋ฉด ๋นํจ์จ์ ์
- ํจ์์ ๋ชฉ์ ์ ๋ช ํํ ํ๊ธฐ๊ฐ ์ด๋ ค์์ง๋ ๊ฒ์ ๋ฌผ๋ก , ํ ์คํธ๋ ์ฝ์ง ์๊ฑฐ๋์ ๋ค๋ฅธ ๋์์ ์ํฅ์ ์ฃผ์ง ์์ผ๋ฉด์ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ๊ธฐ๋ ์ด๋ ค์์ง
- ํจ์๊ฐ ๊ธธ์ด์ง์๋ก ๋ ๋ง์ ๋ณ์๋ฅผ ์ ์ธํด์ผ ํ๊ณ , ๋ฒ์์ ๋ ๋ง์ ๋ณ์๋ฅผ ์ ์ธํ ์๋ก ๊ฐ ๋ณ์์ ๋ชฉ์ ์ ๋ช
ํํ ํ๊ธฐ ์ด๋ ค์์ง
- ์ค์ ๋ณ์๋ฅผ ํ๋์ ๊ตฌ์กฐ์ฒด์ ๋ชจ์์ ๊ทธ ๋ชฉ์ ์ ๋ช ํํ ํ๋ ๊ฒ์ด ์ข์
๐ค ๋ฐ์ด๋๋ฆฌ ํ๋ก์ ํธ์ ๊ด์ฌ ๋ถ๋ฆฌ
- ๋ฐ์ด๋๋ฆฌ ํ๋ก๊ทธ๋จ main ํจ์์ ํฌ๊ธฐ๊ฐ ์ฆ๊ฐ์ ๋ฐ๋ผ ๊ด์ฌ์ ๋ถ๋ฆฌํ๊ธฐ ์ํ ์ง์นจ
- ํ๋ก๊ทธ๋จ์ main.rs์ lib.rs ํ์ผ๋ก ๋ถ๋ฆฌํ๊ณ ํ๋ก๊ทธ๋จ์ ๋ก์ง์ lib.rs ํ์ผ๋ก ์ฎ๊ธด๋ค.
- ๋ช ๋ น์ค ๊ตฌ๋ฌธ๋ถ์ ๋ก์ง์ด ์ถฉ๋ถํ ์๋ค๋ฉด main.rs ํ์ผ์ ๋จ๊ฒจ๋๋ค.
- ๋ช ๋ น์ค ๊ตฌ๋ฌธ๋ถ์ ๋ก์ง์ด ๋ณต์กํด์ง๊ธฐ ์์ํ๋ฉด main.rs ํ์ผ์์ ์ถ์ถํด lib.rs ํ์ผ๋ก ์ฎ๊ธด๋ค.
- main ํจ์์ ๋จ๊ฒจ์ง๋ ์ญํ
- ์ธ์ซ๊ฐ์ ์ด์ฉํด ๋ช ๋ น์ค ๊ตฌ๋ฌธ๋ถ์ ๋ก์ง์ ํธ์ถ
- ๊ธฐํ ๋ค๋ฅธ ์ค์ ์ ์ฉ
- lib.rs ํ์ผ์ run ํจ์ ํธ์ถ
- run ํจ์๊ฐ ์๋ฌ๋ฅผ ๋ฆฌํดํ ๊ฒฝ์ฐ ์ด์ ๋ํ ์ฒ๋ฆฌ
- main.rs ํ์ผ์ ํ๋ก๊ทธ๋จ์ ์คํ์ ๋ด๋นํ๋ฉฐ lib.rs ํ์ผ์ ์ฒ๋ฆฌํ ๋ชจ๋ ์์ ์ ๋ก์ง์ ๋ด๋น
(1) ์ธ์ ๊ตฌ๋ฌธ๋ถ์ ๋ถ๋ฆฌํ๊ธฐ
- main.rs ํ์ผ์์ ์๋ก์ด ํจ์ ์ ์
(2) ์ค์ ๊ฐ์ ๊ทธ๋ฃนํ
๋ณตํฉ ํ์ (complex type)
์ ์ฌ์ฉํ๋ ํธ์ด ๋ ์ ์ ํ ์ํฉ์์ ๊ธฐ๋ณธ ์๋ฃํ์ ์ฌ์ฉํ๋ ๊ฒ์๊ธฐ๋ณธ ์๋ฃํ ๊ฐ๋ฐ(primitive obsession)
์ด๋ผ๋์ํฐ ํจํด(anti-pattern)
์
(3) ๊ตฌ์กฐ์ฒด์ ์์ฑ์
use std::env;
struct Config {
query: String,
filename: String,
}
impl Config {
fn new(args: &[String]) -> Config {
Config {
query: args[1].clone(),
filename: args[2].clone(),
}
}
}
fn main() {
let args = env::args().collect::<Vec<String>>();
let config = Config::new(&args);
let c = std::fs::read_to_string(&config.filename).unwrap();
println!("๊ฒ์์ด: {}\n๋์ ํ์ผ: {}\nํ์ผ ๋ด์ฉ:\n{c}", config.query, config.filename);
}
๊ฒ์์ด: the
๋์ ํ์ผ: poem.txt
ํ์ผ ๋ด์ฉ:
I'm nobody! Who are you?
Are you nobody, too?
Then there's a pair of us - don't tell!
They'd banish us, you know.
How dreary to be somebody!
How public, like a frog
To tell your name the livelong day
To an admiring bog!
๐ค ์๋ฌ ์ฒ๋ฆฌ ๊ฐ์ ํ๊ธฐ
use std::env;
use std::process;
struct Config {
query: String,
filename: String,
}
impl Config {
fn new(args: &[String]) -> Result<Config, &'static str> {
if args.len() < 3 {
return Err("ํ์ํ ์ธ์๊ฐ ์ง์ ๋์ง ์์์ต๋๋ค.");
}
Ok(Config {
query: args[1].clone(),
filename: args[2].clone(),
})
}
}
fn main() {
let args = env::args().collect::<Vec<String>>();
let config = Config::new(&args).unwrap_or_else(
|err| {
println!("์ธ์๋ฅผ ๊ตฌ๋ฌธ๋ถ์ํ๋ ๋์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {}", err);
process::exit(1);
}
);
let c = std::fs::read_to_string(&config.filename).unwrap();
println!("๊ฒ์์ด: {}\n๋์ ํ์ผ: {}\nํ์ผ ๋ด์ฉ:\n{c}", config.query, config.filename);
}
unwrap_or_else
- ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ
Result<T, E>
ํ์ ์ ์ ์ํ ๋ฉ์๋ - Result ๊ฐ์ด Ok ๊ฐ์ด๋ฉด unwrap ๋ฉ์๋์ ์ ์ฌํ๊ฒ ๋์ํจ
- Ok ์ด๊ฒ๊ฐ์ ์ ์ฅ๋ ๊ฐ ๋ฆฌํด
- Err ๊ฐ์ด๋ฉด ํด๋ก์ ๋ฅผ ์ด์ฉํด unwrap_or_else ๋ฉ์๋์ ์ ๋ฌํ ์ต๋ช
ํจ์๋ฅผ ํธ์ถํจ
- ์ ์ ๋ฌธ์์ด์ ์ต๋ช ํจ์์ ํ์ดํ ๋ฌธ์ ์ฌ์ด์ ์ ์ธํ ์ธ์์ ์ ๋ฌ
- ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ
์ธ์๋ฅผ ๊ตฌ๋ฌธ๋ถ์ํ๋ ๋์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: ํ์ํ ์ธ์๊ฐ ์ง์ ๋์ง ์์์ต๋๋ค.
๐ค main ํจ์์์ ๋ก์ง ๋ถ๋ฆฌํ๊ธฐ
use std::env;
use std::process;
struct Config {
query: String,
filename: String,
}
impl Config {
fn new(args: &[String]) -> Result<Config, &'static str> {
if args.len() < 3 {
return Err("ํ์ํ ์ธ์๊ฐ ์ง์ ๋์ง ์์์ต๋๋ค.");
}
Ok(Config {
query: args[1].clone(),
filename: args[2].clone(),
})
}
}
fn run(config: Config) {
let c = std::fs::read_to_string(config.filename)
.unwrap();
println!("ํ์ผ ๋ด์ฉ:\n{c}");
}
fn main() {
let args = env::args().collect::<Vec<String>>();
let config = Config::new(&args).unwrap_or_else(
|err| {
println!("์ธ์๋ฅผ ๊ตฌ๋ฌธ๋ถ์ํ๋ ๋์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {}", err);
process::exit(1);
}
);
println!("๊ฒ์์ด: {}\nํ์ผ ์ด๋ฆ: {}", config.query, config.filename);
run(config);
}
- run ํจ์๋ก ๋ก์ง ๋ถ๋ฆฌ
fn run(config: Config) -> Result<(), Box<dyn Error>> {
let c = std::fs::read_to_string(config.filename)?;
println!("ํ์ผ ๋ด์ฉ:\n{c}");
Ok(())
}
- Result ํ์ ์ ๋ฆฌํดํ๋ run ํจ์
- Ok ์ํฉ์์๋ ์ ๋ ํ์
()
๋ฆฌํด - Err ์ํฉ์์๋ ํธ๋ ์ดํธ ๊ฐ์ฒด์ธ
Box<dyn Error>
๋ฆฌํดBox<dyn Error>
: Error ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๋ ํ์ ์ ๋ฆฌํดํ์ง๋ง, ๋ฆฌํด๋ ๊ฐ์ ํ์ ์ ํน์ ํ์ง๋ ์์- ์ฌ๋ฌ ์๋ฌ ์ํฉ์์ ๊ฐ๊ธฐ ๋ค๋ฅธ ํ์ ์ ๋ฆฌ๋กํ ์ ์๋ ์ ์ฐ์ฑ์ ํ๋ณดํ ์ ์์
- expect ๋ฉ์๋ ๋์ ์
?
์ฐ์ฐ์ ์ฌ์ฉ?
: ์๋ฌ๊ฐ ๋ฐ์ํ ๋ ํ์ฌ ํจ์์ ํธ์ถ์์๊ฒ ์๋ฌ๊ฐ์ ๋ฆฌํดํ ์ ์์
fn main() {
let args = env::args().collect::<Vec<String>>();
let config = Config::new(&args).unwrap_or_else(
|err| {
println!("์ธ์๋ฅผ ๊ตฌ๋ฌธ๋ถ์ํ๋ ๋์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {}", err);
process::exit(1);
}
);
println!("๊ฒ์์ด: {}\nํ์ผ ์ด๋ฆ: {}", config.query, config.filename);
if let Err(e) = run(config) {
println!("์ ํ๋ฆฌ์ผ์ด์
์๋ฌ: {}", e);
process::exit(1);
}
}
- ์์ run ํจ์๋ฅผ ์ฒ๋ฆฌํ๋ main ํจ์
๐ค ์ฝ๋๋ฅผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํฌ๋ ์ดํธ๋ก ๋ถ๋ฆฌํ๊ธฐ
// src/lib.rs
use std::error::Error;
pub struct Config {
pub query: String,
pub filename: String,
}
impl Config {
pub fn new(args: &[String]) -> Result<Config, &'static str> {
if args.len() < 3 {
return Err("ํ์ํ ์ธ์๊ฐ ์ง์ ๋์ง ์์์ต๋๋ค.");
}
Ok(Config {
query: args[1].clone(),
filename: args[2].clone(),
})
}
}
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
let c = std::fs::read_to_string(config.filename)?;
println!("ํ์ผ ๋ด์ฉ:\n{c}");
Ok(())
}
// src/main.rs
use std::{env, process};
use minigrep::Config;
fn main() {
let args = env::args().collect::<Vec<String>>();
let config = Config::new(&args).unwrap_or_else(
|err| {
println!("์ธ์๋ฅผ ๊ตฌ๋ฌธ๋ถ์ํ๋ ๋์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {}", err);
process::exit(1);
}
);
println!("๊ฒ์์ด: {}\nํ์ผ ์ด๋ฆ: {}", config.query, config.filename);
if let Err(e) = minigrep::run(config) {
println!("์ ํ๋ฆฌ์ผ์ด์
์๋ฌ: {}", e);
process::exit(1);
}
}
4๏ธโฃ ํ ์คํธ ์ฃผ๋ ๋ฐฉ๋ฒ์ผ๋ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๊ธฐ๋ฅ ๊ฐ๋ฐํ๊ธฐ
ํ ์คํธ ์ฃผ๋ ๊ฐ๋ฐ(TDD; Test-Driven Development)
- ์คํจํ๋ ํ ์คํธ๋ฅผ ์์ฑํ ๋ค์ ์๋ํ ์ด์ ๋๋ฌธ์ ์คํจํ๋์ง ํ์ธ
- ํ ์คํธ์ ์ฑ๊ณตํ๊ธฐ์ ์ถฉ๋ถํ ์ฝ๋๋ฅผ ์์ฑํ๊ฑฐ๋ ์์
- ์ถ๊ฐํ๊ฑฐ๋ ์์ ํ ์ฝ๋๋ฅผ ๋ฆฌํฉํ ๋งํ๋ฉด์ ํ ์คํธ๊ฐ ๊ณ์ ์ฑ๊ณตํ๋์ง ํ์ธ
- ์ ๊ณผ์ ์ ๊ณ์ ๋ฐ๋ณต
๐ค ์คํจํ๋ ํ ์คํธ ์์ฑํ๊ธฐ
// src/lib.rs
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
vec![]
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn one_result() {
let query = "duct";
let contents = "\
Rust:
safe, fast, productive.
Pick three.";
assert_eq!(
vec!["safe, fast, productive."],
search(query, contents)
);
}
}
- ์ธ์์ ์๋ช
์ด ๋ฆฌํด๊ฐ์ ์๋ช
๊ณผ ์ฐ๊ฒฐ๋์์
- ๋ฆฌํด๋๋ ๋ฒกํฐ๋ contents ์ธ์๋ก ์ ๋ฌ๋ ๋ฌธ์์ด ์ฌ๋ผ์ด์ค๋ฅผ ์ฐธ์กฐํ๋ ์ฌ๋ผ์ด์ค๋ฅผ ํฌํจํ๊ณ ์์ด์ผ ํจ์ ์๋ฏธํจ
- ๋ฌ์คํธ์๊ฒ search ํจ์๊ฐ ๋ฆฌํดํ๋ ๋ฐ์ดํฐ๋ search ํจ์์ contents ์ธ์๋ก ์ ๋ฌ๋ ๋ฐ์ดํฐ์ ๊ฐ์ ์๋ช ์ ๊ฐ์ ธ์ผ ํ๋ค๋ ๊ฒ์ ์๋ ค์ค
running 1 test
thread 'test::one_result' panicked at 'assertion failed: `(left == right)`
left: `["safe, fast, productive."]`,
right: `[]`', src/lib.rs:42:9
...
test test::one_result ... FAILED
failures:
failures:
test::one_result
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
error: test failed, to rerun pass '-p minigrep --lib'
๐ค ํ ์คํธ๊ฐ ์ฑ๊ณตํ๋๋ก ์ฝ๋๋ฅผ ์์ฑํ๊ธฐ
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
let mut v = vec![];
for l in contents.lines() {
if l.contains(query) {
v.push(l);
}
}
v
}
running 1 test
test test::one_result ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
// src/lib.rs
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
let mut f = std::fs::File::open(config.filename)?;
let mut c = String::new();
f.read_to_string(&mut c)?;
for l in search(&config.query, &c) {
println!("{l}");
}
Ok(())
}
- search ํจ์๋ฅผ ํ์ฉํ๋ run ํจ์
Input:
cargo run frog poem.txt
Output:
๊ฒ์์ด: frog
ํ์ผ ์ด๋ฆ: poem.txt
How public, like a frog
Input:
cargo run body poem.txt
Output:
๊ฒ์์ด: body
ํ์ผ ์ด๋ฆ: poem.txt
I'm nobody! Who are you?
Are you nobody, too?
How dreary to be somebody!
Input:
cargo run hihi poem.txt
Ounput:
๊ฒ์์ด: hihi
ํ์ผ ์ด๋ฆ: poem.txt
5๏ธโฃ ํ๊ฒฝ ๋ณ์ ๋ค๋ฃจ๊ธฐ
- ์ฌ์ฉ์๊ฐ ํ๊ฒฝ ๋ณ์๋ฅผ ์ด์ฉํด ๋ฌธ์์ด ๊ฒ์์ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ์ง ์๋๋ก ์ค์ ํ ์ ์๋ ๊ธฐ๋ฅ
๐ค ํ ์คํธ ์์ฑํ๊ธฐ
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
let mut v = vec![];
for l in contents.lines() {
if l.contains(query) {
v.push(l);
}
}
v
}
pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
let query = query.to_lowercase();
let mut v = vec![];
for l in contents.lines() {
if l.to_lowercase().contains(&query) {
v.push(l);
}
}
v
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn case_sensitive() {
let q = "duct";
let c = "\
Rust:
safe, fast, productive.
Pick three.
Duct tape.";
assert_eq!(
vec!["safe, fast, productive."],
search(q, c)
);
}
#[test]
fn case_insensitive() {
let q = "rUsT";
let c = "\
Rust:
safe, fast, productive.
Pick three.
Trust me.";
assert_eq!(
vec!["Rust:", "Trust me."],
search_case_insensitive(q, c)
);
}
}
running 2 tests
test test::case_insensitive ... ok
test test::case_sensitive ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
๐ค ๋ก์ง ์์ ํ๊ธฐ
// src/lib.rs
use std::error::Error;
use std::io::Read;
use std::env;
pub struct Config {
pub query: String,
pub filename: String,
pub case_sensitive: bool,
}
impl Config {
pub fn new(args: &[String]) -> Result<Config, &'static str> {
if args.len() < 3 {
return Err("ํ์ํ ์ธ์๊ฐ ์ง์ ๋์ง ์์์ต๋๋ค.");
}
Ok(Config {
query: args[1].clone(),
filename: args[2].clone(),
case_sensitive: env::var("CASE_INSENSITIVE").is_err()
})
}
}
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
let mut f = std::fs::File::open(config.filename)?;
let mut c = String::new();
f.read_to_string(&mut c)?;
let r = if config.case_sensitive {
search(&config.query, &c)
} else {
search_case_insensitive(&config.query, &c)
};
for l in r {
println!("{l}");
}
Ok(())
}
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
let mut v = vec![];
for l in contents.lines() {
if l.contains(query) {
v.push(l);
}
}
v
}
pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
let query = query.to_lowercase();
let mut v = vec![];
for l in contents.lines() {
if l.to_lowercase().contains(&query) {
v.push(l);
}
}
v
}
std::env
: ํ๊ฒฝ ๋ณ์๋ฅผ ๋ค๋ฃจ๋var
ํจ์๋ฅผ ์ ๊ณตํ๋ ๋ชจ๋- ํ๊ฒฝ ๋ณ์๊ฐ ์ค์ ๋์ด ์์ผ๋ฉด ์ฝ์ด์จ ํ๊ฒฝ ๋ณ์ ๊ฐ์ ์ ์ฅํ Ok ๊ฐ์ ๋ฆฌํดํ๊ณ , ํ๊ฒฝ ๋ณ์๊ฐ ์ค์ ๋์ด ์์ง ์์ผ๋ฉด Err ๊ฐ์ ๋ฆฌํดํ๋ Result ํ์
- Result ๊ฐ์ด ๋ฆฌํด๋๋ฉด is_err ๋ฉ์๋๋ฅผ ์ด์ฉํด ๋ฆฌํด๋ ๊ฐ์ด ์๋ฌ์ธ์ง ํ์ธ
Input:
cargo run to poem.txt
Output:
๊ฒ์์ด: to
ํ์ผ ์ด๋ฆ: poem.txt
Are you nobody, too?
How dreary to be somebody!
Input:
export CASE_INSENSITIVE=1
cargo run to poem.txt
Output:
๊ฒ์์ด: to
ํ์ผ ์ด๋ฆ: poem.txt
Are you nobody, too?
How dreary to be somebody!
To tell your name the livelong day
To an admiring bog!
6๏ธโฃ stderr์ ์ด์ฉํด ์๋ฌ ๋ฉ์์ง ์ถ๋ ฅํ๊ธฐ
println!
๋งคํฌ๋ก๋ ํ์ค ์ถ๋ ฅ์๋ง ์ง์ ๋ ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํ๋ฏ๋ก ํ์ค ์๋ฌ๋ฅผ ์ด์ฉํด ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํ๋ ค๋ฉด ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์ฌ์ฉํด์ผ ํจ
๐ค ์๋ฌ์ ๊ธฐ๋ก ์ฌ๋ถ ํ์ธํ๊ธฐ
- ํ์ค ์๋ฌ ์คํธ๋ฆผ์ ํ์ผ๋ก ๋ฆฌ๋ค์ด๋ ํธํ์ง ์์ผ๋ฏ๋ก ํ์ค ์๋ฌ์ ์ถ๋ ฅ๋ ๋ฉ์์ง๋ ํ๋ฉด์ ํตํด ํ์ธํ ์ ์์
- ํ์ค ์ถ๋ ฅ ์คํธ๋ฆผ์ ํ์ผ๋ก ๋ฆฌ๋ค์ด๋ ํธํ ์ํฉ์์๋ ์๋ฌ ๋ฉ์์ง๋ ํ์ค ์๋ฌ ์คํธ๋ฆผ์ ์ถ๋ ฅํด์ ํ๋ฉด์ผ๋ก ๋ฉ์์ง๋ฅผ ํ์ธํ ์ ์๋๋ก ๊ตฌํ
cargo run > output.txt
// output.txt
์ธ์๋ฅผ ๊ตฌ๋ฌธ๋ถ์ํ๋ ๋์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: ํ์ํ ์ธ์๊ฐ ์ง์ ๋์ง ์์์ต๋๋ค.
๐ค ์๋ฌ๋ฅผ stderr์ ์ถ๋ ฅํ๊ธฐ
use std::{env, process};
use minigrep::Config;
fn main() {
let args = env::args().collect::<Vec<String>>();
let config = Config::new(&args).unwrap_or_else(
|err| {
eprintln!("์ธ์๋ฅผ ๊ตฌ๋ฌธ๋ถ์ํ๋ ๋์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {}", err);
process::exit(1);
}
);
println!("๊ฒ์์ด: {}\nํ์ผ ์ด๋ฆ: {}", config.query, config.filename);
if let Err(e) = minigrep::run(config) {
eprintln!("์ ํ๋ฆฌ์ผ์ด์
์๋ฌ: {}", e);
process::exit(1);
}
}
- ํ์ค ์๋ฌ ์คํธ๋ฆผ์ ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํ๋
eprintln!
๋งคํฌ๋ก ์ฌ์ฉ - ํ๋ก๊ทธ๋จ์ ์คํ ์ฑ๊ณต ๋ฉ์์ง๋ ํ์ค ์ถ๋ ฅ์ผ๋ก ์ถ๋ ฅํ๊ณ ์๋ฌ ๋ฉ์์ง๋ ํ์ค ์๋ฌ์ ์ถ๋ ฅ
Summary
- ๋ช
๋ น์ค ์ธ์, ํ์ผ, ํ๊ฒฝ ๋ณ์, ๊ทธ๋ฆฌ๊ณ ์๋ฌ์ ์ถ๋ ฅ์ ์ํ
eprintln!
๋งคํฌ๋ก ๋ฑ์ ๋ช ๋ น์ค ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํ๊ธฐ ์ํ ๊ธฐ๋ณธ์ ์ธ ๋๊ตฌ๋ค
728x90
๋ฐ์ํ
'Development Study > Rust' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Rust] How to study Rust? - "Copycat" (2) (0) | 2023.08.28 |
---|---|
[Rust] How to study Rust? - "Copycat" (1) (0) | 2023.08.25 |
[Rust] Start Rust (Day 20) - Writing Automated Tests (0) | 2023.08.19 |
[Algorithm] Baekjoon - 2์ฐจ์ ๋ฐฐ์ด ๋จ๊ณ (0) | 2023.08.10 |
[Algorithm] Baekjoon - ์ฌํ 1 ๋จ๊ณ (0) | 2023.08.03 |
Comments