从零使用 Rust 实现一个天气命令行工具
本篇使用 Rust 实现一个输入城市名来获取当地天气的命令行工具
本篇文章同时收录在公众号《泡芙学前端》,持续更新文章中,欢迎大家关注~
目标
这里我们在 Windows 上实现,所以最终实现出来的效果就是这样的:
命令行输入获取北京天气:
weather beijing
输出:
-----正在获取天气信息, 请稍后...-----
当前温度:297.09℃
当前最低温:297.09℃
当前最高温:297.09℃
体感温度:295.7℃
湿度:6%
今日日出时间:04:55:54
今日日落时间:19:26:10
所在经度:116.3972
所在纬度:39.9075
接口
这里我们使用一个 免费的天气 API,然后注册一个账号,接下来到这里申请一个 API KEY
调用方式:
https://api.openweathermap.org/data/2.5/weather?q={city name}&appid={API key}
比如:
https://api.openweathermap.org/data/2.5/weather?q=beijing&appid=xxx
目录结构
这次的目录结构比较简单哈,main.rs 编写入口代码, handler 编写主要逻辑
weather
├── Cargo.lock
├── Cargo.toml
├── README.md
├── src
│ ├── handler
│ │ └── mod.rs
│ └── main.rs
安装依赖
[package]
edition = "2021"
name = "weather"
version = "0.1.0"
[dependencies]
chrono = "0.4.19" # 时间格式化工具
colored = "2.0.0" # 控制台上色
exitfailure = "0.5.1" # 错误处理
reqwest = {version = "0.11", features = ["json"]} # 发送网络请求
serde = "1.0.114"
serde_derive = "1.0.114"
serde_json = "1.0.56"
structopt = "0.3.21" # 解析命令行参数
tokio = {version = "1", features = ["full"]}
接下来安装依赖,运行 cargo install
开始编码
有了上面的准备工作,我们就能够开始写应用了,src/main.rs
mod handler;
use handler::{print_response, Weather};
use exitfailure::ExitFailure;
use structopt::StructOpt;
#[derive(StructOpt, Debug)]
pub struct Input {
pub city: String,
}
#[tokio::main]
async fn main() -> Result<(), ExitFailure> {
// 获取命令行输入的参数,第一个参数即是 city name
let input = Input::from_args();
match Weather::get(&input.city).await {
Ok(r) => print_response(&r),
Err(e) => println!("请求出错,{:?}", &e),
};
Ok(())
}
src/handler/mod.rs
编写主要逻辑
use chrono::prelude::*;
use colored::*;
use std::time::{Duration, UNIX_EPOCH};
use exitfailure::ExitFailure;
use reqwest::Url;
use serde_derive::{Deserialize, Serialize};
/// 定义接口返回的数据结构
#[derive(Deserialize, Serialize, Debug)]
pub struct Weather {
main: Temperature,
sys: Sys,
coord: Coord,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Temperature {
temp: f64,
temp_min: f64,
temp_max: f64,
feels_like: f64,
humidity: f64,
}
#[derive(Deserialize, Serialize, Debug)]
pub struct Coord {
lon: f64,
lat: f64,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Sys {
sunrise: i32,
sunset: i32,
}
/// 定义天气接口的实现
impl Weather {
pub async fn get(city: &String) -> Result<Self, ExitFailure> {
println!("{}", "-----正在获取天气信息, 请稍后...-----".bright_green());
let url = format!("http://api.openweathermap.org/data/2.5/weather?q={}&APPID=自己去申请一下
", city);
let url = Url::parse(url.as_str())?;
let response = reqwest::get(url).await?.json::<Weather>().await?;
Ok(response)
}
}
/// 格式化时间,将时间戳转成指定格式
pub fn formate_timestamp(timestamp: i32, format: &str) -> String {
let time = UNIX_EPOCH + Duration::from_secs(timestamp as u64);
let datetime = DateTime::<Local>::from(time);
datetime.format(format).to_string()
}
/// 打印返回结果到控制台
pub fn print_response(resp: &Weather) {
println!(
" 当前温度:{}℃ \n 当前最低温:{}℃ \n 当前最高温:{}℃ \n 体感温度:{}℃ \n 湿度:{}% \n 今日日出时间:{} \n 今日日落时间:{} \n 所在经度:{} \n 所在纬度:{}",
resp.main.temp.to_string().bright_red(),
resp.main.temp_min,
resp.main.temp_max,
resp.main.feels_like,
resp.main.humidity,
formate_timestamp(resp.sys.sunrise, "%H:%M:%S"),
formate_timestamp(resp.sys.sunset, "%H:%M:%S"),
resp.coord.lon,
resp.coord.lat
);
}
/// 时间戳的单测
#[test]
fn test_timestamp_to_time() {
assert_eq!(
formate_timestamp(1643467428, "%H:%M:%S"),
"22:43:48".to_string()
);
assert_eq!(
formate_timestamp(1643467428, "%Y-%m-%d %H:%M:%S"),
"2022-01-29 22:43:48".to_string()
)
}
打包和配置
最后我们编写完代码之后,就要进行打包了,控制台运行
cargo build --release
打包完成后,可以看到 target/release/weather.exe
文件
接下来我们就可以到环境变量中配置上这个文件了
最后我们就能够在系统任意地方打开控制台查看当前的天气
完结~~
欢迎关注公众号《泡芙学前端》,持续更新文章中...
转载自:https://juejin.cn/post/7235283785260302392