文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Golang和Rust语言常见功能/库

2024-12-03 18:13

关注

参数处理

Golang标准库中提供了功能。flag库是非常基础的功能,在实践上也非常有用,在做命令行交互程序时候必不可少。

  1. package main 
  2. import "flag" 
  3. var ( 
  4. program = flag.String("p", "", "h program to compile/run") 
  5. outFname = flag.String("o", "", "if specified, write the webassembly binary created by -p here") 
  6. watFname = flag.String("o-wat", "", "if specified, write the uncompiled webassembly created by -p here") 
  7. port = flag.String("port", "", "HTTP port to listen on") 
  8. writeTao = flag.Bool("koan", false, "if true, print the h koan and then exit") 
  9. writeVersion = flag.Bool("v", false, "if true, print the version of h and then exit") 

上述代码会生成一些程序包全局变量,其中将包含命令行参数的值。

在Rust中,常用的命令行解析包是structopt。但是,其工作方式与Golang flag程序包有所不同。structopt会选项加载到结构中,而非全局可变变量。主要因为Rust语言编程实践中,基本上都会避免全局可变的变量。在大多数情况下,带有包的全局变量flag是可以的,但前提是必须在程序真正开始执行其需要做的工作之前将它们写入到程序中。

一个简单示例源自于pahi库源码:

  1. #[derive(Debug, StructOpt)] 
  2. #[structopt( 
  3. name = "pa'i"
  4. about = "A WebAssembly runtime in Rust meeting the Olin ABI." 
  5. )] 
  6. struct Opt { 
  7. #[structopt(short, long, default_value = "cranelift")] 
  8. backend: String, 
  9. #[structopt(short, long)] 
  10. function_log: bool, 
  11. #[structopt(short, long)] 
  12. no_cache: bool, 
  13. #[structopt()] 
  14. fname: String, 
  15. #[structopt(short, long, default_value = "_start")] 
  16. entrypoint: String, 
  17. #[structopt()] 
  18. args: Vec<String>

Rust编译器会生成所需的参数解析代码,然后可以使用:

  1. fn main() { 
  2. let opt = Opt::from_args(); 
  3. debug!("args: {:?}", opt.args); 
  4. if opt.backend != "cranelift" { 
  5.         return Err(format!( 
  6.             "wanted backend to be cranelift, got: {}", 
  7.             opt.backend 
  8.         )); 

错误处理

Golang的标准库具有error接口,可以创建一个描述类型的函数,函数描述为什么功能无法按预期执行,Golang程序必须先做好错误处理。比如:

  1. func Write(w io.Writer, buf []byte) error { 
  2. _, err :w.Write(buf) 
  3. if err != nil { 
  4. log.Println("unable to write:", err) 
  5. return err 
  6. return nil 

Rust也具有Error 特性,它使还可以创建一个描述函数为何无法实现其预期功能的类型。这儿我们介绍更加易用的thiserror板条箱构建自定义错误类型:

  1. [dependencies] 
  2. thiserror = "1" 

然后,在程序中使用:

  1. use std::fmt; 
  2. use thiserror::Error; 
  3. #[derive(Debug, Error)] 
  4. struct Divide0​; 
  5. impl fmt::Display for Divide0​ { 
  6. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 
  7. write!(f, "不能被零整除!") 

日志记录

Go标准库中也自带了log库。该库是一个非常有争议的记录器,它的日志记录缺乏日志记录级别和上下文感知值之类的功能。

  1. package main 
  2. import ( 
  3. "log" 
  4. func init() { 
  5. log.SetPrefix("TRACE: ") 
  6. log.SetFlags(log.Ldate | log.Lmicroseconds | log.Llongfile) 
  1. func main() { 
  2. log.Println("message") 
  3. log.Fatalln("fatal message") 
  4. log.Panicln("panic message") 
  1. ------------------------------- 
  2. TRACE: 2020/09/09 14:24:32.868375 TestLog.go:15: message 
  3. TRACE: 2020/09/09 14:24:32.962329 TestLog.go:18: fatal message 
  4. Process finished with exit code 1 

在Rust中,有一个板条箱,这是一个非常简单的包,它使用error!,warn!,info!,debug!和trace!宏分别关联到最高和最低日志打印水平。同样要使用log板条箱,先要增加的项目中,即添加到Cargo.toml的依赖部分。

  1. [dependencies] 
  2. log = "0.4" 

然后,就可以使用了:

  1. use log::{error, warn, info, debug, trace}; 
  2. fn main() { 
  3. trace!("starting main"); 
  4. debug!("debug message"); 
  5. info!("this is some information"); 
  6. warn!("oh no something bad is about to happen"); 
  7. error!("oh no it's an error"); 

注意,默认该库日志记录是不会记录到本地文件中的。要记录日志还需要其他库。

pretty_env_logger是和log买一送一,最常搭配使用的板条箱。同样,先添加项目依赖:

  1. [dependencies] 
  2. log = "0.4" 
  3. pretty_env_logger = "0.4" 

然后,在代码中使用:

  1. use log::{error, warn, info, debug, trace}; 
  2. fn main() { 
  3. pretty_env_logger::init(); 
  4. trace!("这是一个示例程序。"); 
  5. debug!("调试信息xxx。"); 
  6. info!("程序正在运行中。"); 
  7. warn!("[WARN]程序有些参数配置有问题。"); 
  8. error!("[ERROR]程序发生严重错误!"); 

然后在启动时候增加,日志级别参数RUST_LOG=trace 运行:

  1. env RUST_LOG=trace cargo run 
  2.   
  3. Compiling errex v0.1.0 (/home/lz/test/rust/commoncrate/errex) 
  4.     Finished dev [unoptimized + debuginfo] target(s) in 1.32s 
  5.      Running `target/debug/errex` 
  6.  TRACE errex > 这是一个示例程序。 
  7.  DEBUG errex > 调试信息xxx。 
  8.  INFO  errex > 程序正在运行中。 
  9.  WARN  errex > [WARN]程序有些参数配置有问题。 
  10.  ERROR errex > [ERROR]程序发生严重错误! 

序列化/反序列化

Golang在标准库内置了 包用来实现JSON编码/解码功能。我们可以定义可以轻松读取和写入JSON的类型。下面一个例子:

  1. "id": 3137, 
  2. "author": { 
  3. "id": 420, 
  4. "name": "Chongchong" 
  5. }, 
  6. "body": "Hello,This is Chongchong web!", 
  7. "in_reply_to": 3135 

在Golang中,可以生成如下的结构体:

  1. type Author struct { 
  2. ID int `json:"id"` 
  3. Name string `json:"name"` 
  1. type Comment struct { 
  2. ID int `json:"id"` 
  3. Author Author `json:"author"` 
  4. Body string `json:"body"` 
  5. InReplyTo int `json:"in_reply_to"` 

Rust没有开箱即用的功能,需要使用第三方板条箱,最常用的一个库是serde,可以跨JSON和能想到的所有其他序列化方法使用。

  1. [dependencies] 
  2. serde = { version = "1"features = ["derive"] } 
  3. serde_json = "1" 

注意,上面serde的依赖配置,和其他包有差异。

Golang的JSON包通过使用struct标签作为元数据来工作,但是Rust没有,需要改用Rust的衍生功能。

因此,要将serde用于的注释类型:

  1. use serde::{Deserialize, Serialize}; 
  2. #[derive(Clone, Debug, Deserialize, Serialize)] 
  3. pub struct Author { 
  4. pub id: i32, 
  5. pub name: String, 
  6. #[derive(Clone, Debug, Deserialize, Serialize)] 
  7. pub struct Comment { 
  8. pub id: i32, 
  9. pub author: Author, 
  10. pub body: String, 
  11. pub in_reply_to: i32, 

然后,使用以下代码解析Json:

  1. fn main() { 
  2. let data = r#" 
  3. "id": 3137, 
  4. "author": { 
  5. "id": 420, 
  6. "name": "Chongchong" 
  7. }, 
  8. "body": "Hello,This is Chongchong web!", 
  9. "in_reply_to": 3135 
  10. "#; 
  11. let c: Comment = serde_json::from_str(data).expect("json to parse"); 
  12. println!("comment: {:#?}", c); 

cargo run

  1. ... 
  2. Finished dev [unoptimized + debuginfo] target(s) in 0.04s 
  3.      Running `target/debug/serdeex` 
  4. comment: Comment { 
  5.     id: 3137, 
  6.     author: Author { 
  7.         id: 420, 
  8.         name: "Chongchong", 
  9.     }, 
  10.     body: "Hello,This is Chongchong web!", 
  11.     in_reply_to: 3135, 

Web开发

在Web开发中HTTP包必不可少的。Golang中可使用net/http充当生产级HTTP客户端和服务器。

  1. import ( 
  2. "net/http" 
  3. "fmt" 
  4. "log" 
  5.  
  6. func sayhelloGolang(w http.ResponseWriter, r *http.Request) { 
  7. r.ParseForm() 
  8. fmt.Println("path", r.URL.Path) 
  9. w.Write([]byte("Hello Chongchong!")) 
  10.  
  11. func main() { 
  12. http.HandleFunc("/",hello) 
  13. err :http.ListenAndServe(":8080", nil) 
  14. if err != nil { 
  15. log.Fatal("ListenAndServe: ", err) 

它可以让我们非常轻松地进行Web开发。Rust标准库没有开箱即用的HTTP功能,但是Web的框架也非常丰富。

客户端

对于HTTP客户端,可以使用。它还可以与serde无缝集成,以允许从HTTP解析JSON:

  1. [dependencies] 
  2. reqwest = { version = "0.10"features = ["json"] } 
  3. tokio = { version = "0.2"features = ["full"] } 

tokio默认情况下Rust不附带异步运行时,tokio大约等同于Golang运行时帮助处理的大多数重要事项。简单实例如下:


运行此命令:

  1. cargo run  
  2. ... 
  3. Finished dev [unoptimized + debuginfo] target(s) in 3.31s 
  4.      Running `target/debug/webcer` 
  5. Status: 200 OK 
  6. Body: 
  7. > 
  8. <html> 
  9.   <head> 
  10.     <meta charset="utf-8"> 
  11. <meta http-equiv="X-UA-Compatible" content="chrome=1"> 
  12. <title>hyper.rs | hypertitle> 
  13. <meta name="description" content=""> 

结合其他功能,reqwest可以做作为一个功能强大的HTTP客户端。

服务器端

至于HTTP服务器,可以使用warp板条箱。warp是一个建立在Rust的类型系统之上的HTTP服务器框架。

  1. [dependencies] 
  2. tokio = { version = "0.2"features = ["macros"] } 
  3. warp = "0.2" 

让我们写个简单的"Hello,Chongchong"示例:

  1. use warp::Filter; 
  2. #[tokio::main] 
  3. async fn main() { 
  4. // GET /hello/Chongchong=> 200 OK with body "Hello, Chongchong!" 
  5. let hello = warp::path!("hello" / String) 
  6. .map(|name| format!("Hello, {}!", name)); 
  7. warp::serve(hello) 
  8. .run(([127, 0, 0, 1], 3030)) 
  9. .await; 

然后通过127.0.0.1:3030/hello/Chongchong,就可以提示Hello, Chongchong!。

对 warp应用可以使用其or模式构建多条Web路由:

  1. let hello = warp::path!("hello" / String) 
  2. .map(|name| format!("Hello, {}!", name)); 
  3. let health = warp::path!(".within" / "health") 
  4. .map(|| "OK"); 
  5. let routes = hello.or(health); 

还可通过过滤器将其他数据类型注入到处理程序中:

  1. let fact = { 
  2. let facts = pfacts::make(); 
  3. warp::any().map(move || facts.clone()) 
  4. }; 
  5. let fact_handler = warp::get() 
  6. .and(warp::path("fact")) 
  7. .and(fact.clone()) 
  8. .and_then(give_fact); 

warp是功能强大的HTTP服务器,可以跨生产级Web应用程序所需的所有内容工作。

模版

Web开发中要常用模版来特定化页面的输出。Golang的标准库还包括HTML和纯文本模板包html/template和text/template。在Rust中有很多用于HTML模板化的解决方案,比如ructe板条箱。ructe使用Cargo的build.rs功能在编译时为其模板生成Rust代码。这样就可以将HTML模板编译成结果应用程序二进制文件,从而以惊人的速度呈现它们。

添加Cargo.toml:

  1. [build-dependencies] 
  2. ructe = { version = "0.12"features = ["warp02"] } 
  3. 还依赖mime板条箱: 
  1. [dependencies] 
  2. mime = "0.3.0" 

完成此操作后,templates在当前工作目录中创建一个新文件夹。创建一个名为的文件hello.rs.html,并将以下内容放入其中:

  1. @(title: String, message: String) 
  2. <html> 
  3. <head> 
  4. <title>@titletitle> 
  5. head> 
  6. <body> 
  7. <h1>@titleh1> 
  8. <p>@messagep> 
  9. body> 
  10. html> 

然后使用模板templates.rs:

  1. use warp::{http::Response, Filter, Rejection, Reply}; 
  2. async fn hello_html(message: String) -> Result<impl Reply, Rejection> { 
  3. Response::builder() 
  4. .html(|o| templates::index_html(o, "Hello".to_string(), message).unwrap().clone())) 

在src/main.rs底部,通过以下语句引入模版定义:

  1. include!(concat!(env!("OUT_DIR"), "/templates.rs")); 

在main()函数中调用:

  1. let hello_html_rt = warp::path!("hello" / "html" / String) 
  2. .and_then(hello_html); 
  3. let routes = hello_html_rt.or(health).or(hello); 

总结

本文我们介绍了Golang和Rust中常用的功能包括命令行参数解析、错误处理、日志、Json处理和Web库,我们可以发现基本上这些功能都在Golang标准库中都提供了,而Rust则要引入额外的板条箱,但是借助强大的Cargo包管理工具,其使用也非常便捷。

 

来源:今日头条内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯