likes
comments
collection
share

从零使用 Rust 实现一个天气命令行工具

作者站长头像
站长
· 阅读数 17

本篇使用 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 文件

接下来我们就可以到环境变量中配置上这个文件了

从零使用 Rust 实现一个天气命令行工具 最后我们就能够在系统任意地方打开控制台查看当前的天气

从零使用 Rust 实现一个天气命令行工具

完结~~

欢迎关注公众号《泡芙学前端》,持续更新文章中...