このPRで、Cargoもfailure
からanyhowに移行したらしい。
まずはanyhow
を試してみる。
use anyhow::Result
で使う。
extern crate anyhow;
extern crate serde;
extern crate serde_json;
use anyhow::Result;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct ClusterMap {
name: String,
group: i32,
}
fn get_cluster_info() -> Result<ClusterMap> {
let config = std::fs::read_to_string("cluster.json")?;
let map: ClusterMap = serde_json::from_str(&config)?;
Ok(map)
}
fn main() {
let cm = get_cluster_info().unwrap();
println!("{:?}", cm);
}
利用するjson
{
"name": "cluster A",
"group": 1
}
実行結果
❯ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/myanyhow`
ClusterMap { name: "cluster A", group: 1 }
❯ cargo run
Compiling myanyhow v0.1.0 (/Users/cipepser/.go/src/github.com/cipepser/rust-anyhow-sample/myanyhow)
Finished dev [unoptimized + debuginfo] target(s) in 0.49s
Running `target/debug/myanyhow`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: No such file or directory (os error 2)', src/libcore/result.rs:1165:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
group
をstringにしてみる。
{
"name": "cluster A",
"group": "1"
}
❯ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/myanyhow`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: invalid type: string "1", expected i32 at line 3 column 14', src/libcore/result.rs:1165:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
main
もpanic
させずに、err
を表示させるようにした。
extern crate anyhow;
extern crate serde;
extern crate serde_json;
use anyhow::{Context, Result};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct ClusterMap {
name: String,
group: i32,
}
fn get_cluster_info() -> Result<ClusterMap> {
let config = std::fs::read_to_string("cluster.json")
.context("failed to read config file")?;
let map: ClusterMap = serde_json::from_str(&config)?;
Ok(map)
}
fn main() {
let _ = match get_cluster_info() {
Ok(cm) => println!("{:?}", cm),
Err(err) => println!("{:?}", err),
};
}
❯ cargo run
failed to read config file
Caused by:
No such file or directory (os error 2)
extern crate anyhow;
extern crate serde;
extern crate serde_json;
use anyhow::{Context, Result};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct ClusterMap {
name: String,
group: i32,
}
fn get_cluster_info(path: &str) -> Result<ClusterMap> {
let config = std::fs::read_to_string(&path)
.with_context(|| format!("failed to read config file: {}", path))?;
let map: ClusterMap = serde_json::from_str(&config)?;
Ok(map)
}
fn main() {
let _ = match get_cluster_info("cluster.json") {
Ok(cm) => println!("{:?}", cm),
Err(err) => println!("{:?}", err),
};
}
❯ cargo run
failed to read config file: cluster.json
Caused by:
No such file or directory (os error 2)
thiserror
を追加して、独自エラーとしてClusterMapError
を定義。
validate
でgroup
の範囲を0-100
とし、範囲外の場合は、InvalidGroup(i32)
を返す仕様とした。
extern crate anyhow;
extern crate serde;
extern crate serde_json;
extern crate thiserror;
use anyhow::{Context, Result};
use serde::{Serialize, Deserialize};
use thiserror::Error;
use crate::ClusterMapError::InvalidGroup;
#[derive(Serialize, Deserialize, Debug)]
struct ClusterMap {
name: String,
group: i32,
}
#[derive(Error, Debug)]
pub enum ClusterMapError {
#[error("Invalid range of range (expected in 0-100), got {0}")]
InvalidGroup(i32),
}
impl ClusterMap {
fn validate(self) -> Result<Self> {
if self.group < 0 || self.group > 100 {
Err(InvalidGroup(self.group).into())
} else {
Ok(self)
}
}
}
fn get_cluster_info(path: &str) -> Result<ClusterMap> {
let config = std::fs::read_to_string(&path)
.with_context(|| format!("failed to read config file: {}", path))?;
let map: ClusterMap = serde_json::from_str(&config)?;
let map = map.validate()?;
Ok(map)
}
fn main() {
let _ = match get_cluster_info("cluster.json") {
Ok(cm) => println!("{:?}", cm),
Err(err) => println!("{:?}", err),
};
}
利用するjson
{
"name": "cluster A",
"group": 101
}
実行結果
❯ cargo run
Invalid range of range (expected in 0-100), got 101
[dependencies]
anyhow = "1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.44"
thiserror = "1.0"