Gostd is the golang standard library implementation in rust-lang.
Gostd是rust-lang中的golang标准库实现。
rust 语法比go复杂,但是go代码简单好理解,想通过这个项目把go的标准库通过rust实现。以后有什么go的项目可以通过它方便翻译代码到rust,比如把 import "bytes" 改成 use gostd::bytes 就可以实现转换。
本项目纯粹个人兴趣,大概率会失败,但是梦想还是要有的万一它实现了。
go to rust,to be rust or to be failed.
go底层特性可能无法用rust实现,比如跟运行时相关的反射reflect,如果有依赖此库需要通过rust中的方式处理。
基础数据类型的转换,比如string是否采用自定义类型比如GoString来实现还是用string,float64(go) -> f64(rust)等等。
还有指针类型,幸好go的指针操作相比rust要少。
go中的接口如何用rust的trait的实现?个人感觉还相对比较容易
go中的不定参数在rust中只能用宏实现,这个比较麻烦,个人目前还不知道宏能不能像方法一样绑定到sturct上。
需要用rust实现的go标准库列表,go.1.17.1代码做参考。
go 这个包不会实现,因为我们转换成rust基本用不上这个包。
├── archive
├── bufio
├── builtin
├── bytes
├── cmd
├── compress
├── container
├── context
├── crypto
├── database
├── debug
├── embed
├── encoding
├── errors
├── expvar
├── flag
├── fmt
├── go
├── hash
├── html
├── image
├── index
├── internal
├── io
├── log
├── math
├── mime
├── net
├── os
├── path
├── plugin
├── reflect
├── regexp
├── runtime
├── sort
├── strconv
├── strings
├── sync
├── syscall
├── testdata
├── testing
├── text
├── time
├── unicode
├── unsafe
└── vendor
use gostd::archive
use gostd::bufio
use gostd::builtin
use gostd::bytes
use gostd::cmd
use gostd::compress
use gostd::container
use gostd::context
use gostd::crypto
use gostd::database
use gostd::debug
use gostd::embed
use gostd::encoding
use gostd::errors
use gostd::expvar
use gostd::flag
use gostd::fmt
use gostd::go
use gostd::hash
use gostd::html
use gostd::image
use gostd::index
use gostd::internal
use gostd::io
use gostd::log
use gostd::math
use gostd::mime
use gostd::net
use gostd::os
use gostd::path
use gostd::plugin
use gostd::reflect
use gostd::regexp
use gostd::runtime
use gostd::sort
use gostd::strconv
use gostd::strings
use gostd::sync
use gostd::syscall
use gostd::testdata
use gostd::testing
use gostd::text
use gostd::time
use gostd::unicode
use gostd::unsafe
use gostd::vendor
分析go标准库的依赖情况,从最底层的库开始实现。
go源码中的单元测试也会一并用rust实现,这样可以保证代码的健壮性。
Go基础类型在rust实现,在gostd::builtin 中,比如 int64 = i64, int32 = i32
强制转换宏,例如 2 as i64 等价 int64!(2) 跟Go的int64(2)就多个!
time库在rust实现 gostd::time
time库支持macOSX 和linux平台,通过libc库调用C函数实现 time::Now()
time,支持各种格式显示时间。
docs.rs文档增加例子程序"RUN"按钮,但是要复制代码本地运行,在rust play运行不了(因为下载量没到前100)。
time支持local时区信息自动从系统读取,可以用time::Now()获取本地时间。
strings模块,字符串处理函数已完成。除了Reader相关方法还没全实现。(version >=0.2.3)
strings模块, 完成剩余的方法实现。(version >=0.2.4)
io模块,完成部分接口例如Reader,Writer等。(version >=0.2.4)
http模块的client客户端功能,支持http和https。(version >=0.2.6)
完成bytes模块。(version >=0.2.8)
完成mime::multipart模块。(version >=0.3.1)
修复windos10平台编译失败的bug。(version>=0.3.18)
对net/http模块,自定义错误处理上的优化,引入bytes提高性能,api会有参数类型的变化(version>=0.4.1)
对net/http模块,增加异步编程的支持,独立一个模块async_http支持异步编程,原来模块保持不变。(version>=0.4.3)
net::http,net::url,io,strings,unicode,bytes 独立发布包。
独立发布gostd_time,代码等价于 use gostd::time 。
独立发布gostd_builtin, 代码等价于 use gostd::builtin 。
独立发布gostd_unicode, 代码等价于 use gostd::unicode 。
独立发布gostd_http, 代码等价于 use gostd::net::http 。
独立发布gostd_strings, 代码等价于 use gostd::strings 。
独立发布gostd_bytes, 代码等价于 use gostd::bytes 。
独立发布gostd_url, 代码等价于 use gostd::net::url 。
独立发布gostd_io, 代码等价于 use gostd::io 。
use gostd:: bytes;
use gostd:: mime:: multipart:: Writer ;
use gostd:: net:: http:: { Client , Method , Request } ;
fn main ( ) -> Result < ( ) , std:: io:: Error > {
let mut body = bytes:: Buffer :: new ( ) ;
let mut w = Writer :: new ( & mut body) ;
w. WriteField ( "requestId" , "12121231231" ) ?;
w. WriteField ( "name" , "刘xxx" ) ?;
w. Close ( ) ?;
let contentType = w. FormDataContentType ( ) ;
let url = "http://www.baidu.com" ;
let mut req = Request :: New ( Method :: Post , url, Some ( body. Bytes ( ) . into ( ) ) ) ?;
req. Header . Set ( "Content-Type" , contentType. as_str ( ) ) ;
let mut client = Client :: New ( ) ;
let response = client. Do ( & mut req) ?;
println ! (
"{}" ,
String :: from_utf8( response. Body . unwrap( ) . to_vec( ) ) . unwrap( )
) ;
Ok ( ( ) )
}
use gostd:: bytes;
use gostd:: mime:: multipart:: Writer ;
use gostd:: net:: http:: { Client , Method , Request } ;
use std:: fs;
fn main ( ) -> anyhow:: Result < ( ) > {
let mut body = bytes:: Buffer ::new ( ) ;
let mut w = Writer :: new ( & mut body) ;
// 1. 添加普通文本字段
w. WriteField ( "title" , "测试上传附件" ) ?;
// 2. 创建文件表单部分
// CreateFormFile 返回底层 buffer 的可变引用,可直接写入文件字节
let mut file_part = w. CreateFormFile ( "file_field_name" , "example.txt" ) ?;
// 3. 读取本地文件并写入
let content = fs:: read ( "test_file.txt" ) ?;
file_part. Write ( content) ?;
// 4. 关闭 Writer 以写入最后的 boundary 边界
w. Close ( ) ?;
let contentType = w. FormDataContentType ( ) ;
let url = "http://example.com/api/upload" ;
let mut req = Request :: New ( Method :: Post , url, Some ( body. Bytes ( ) . into ( ) ) ) ?;
req. Header . Set ( "Content-Type" , contentType. as_str ( ) ) ;
let mut client = Client :: New ( ) ;
let response = client. Do ( & mut req) ?;
println ! ( "Response status: {}" , response. Status ) ;
Ok ( ( ) )
}
默认不启用异步方式
features =["async-std-rt"] // 使用async_std 异步运行时
或者 features =["tokio-rt"] // 使用 tokio 异步运行时
Cargo.toml配置:
async-std = {version = "1.13" ,features = ["attributes"]}
gostd = { version = "0.4" ,features =["async-std-rt"]}
POST
use gostd:: net:: http:: async_http
#[ async_std:: main]
async fn main ( ) -> anyhow:: Result < ( ) > {
let url = "https://petstore.swagger.io/v2/pet" ;
let postbody = r#"{"id":0,"category":{"id":0,"name":"string"},"name":"doggie","photoUrls":["string"],"tags":[{"id":0,"name":"string"}],"status":"available"}"#
. as_bytes ( )
. to_vec ( ) ;
let response = async_http:: Post ( url, "application/json" , Some ( postbody. into ( ) ) ) . await ?;
println ! (
"{}" ,
String :: from_utf8( response. Body . expect( "return body error" ) . to_vec( ) ) . unwrap( )
) ;
Ok ( ( ) )
}
或者
use gostd:: net:: http:: { async_http:: AsyncClient , Method , Request } ;
#[ async_std:: main]
async fn main ( ) -> anyhow:: Result < ( ) > {
let url = "https://petstore.swagger.io/v2/pet" ;
let postbody = r#"{
"id": 0,
"category": {
"id": 0,
"name": "string"
},
"name": "doggie",
"photoUrls": [
"string"
],
"tags": [
{
"id": 0,
"name": "string"
}
],
"status": "available"
}"#
. as_bytes ( )
. to_vec ( ) ;
let mut req = Request :: New ( Method :: Post , url, Some ( postbody. into ( ) ) ) ?;
req. Header . Set ( "accept" , "application/json" ) ;
req. Header . Set ( "Content-Type" , "application/json" ) ;
let mut client = AsyncClient :: New ( ) ;
let response = client. Do ( & mut req) . await ?;
println ! (
"{}" ,
String :: from_utf8( response. Body . expect( "return body error" ) . to_vec( ) ) . unwrap( )
) ;
Ok ( ( ) )
}
// output
// {"id":92233723685477587,"category":{"id":,"name":"string"},"name":"doggie","photoUrls":["string"],"tags":[{"id":,"name":"string"}],"status":"available"}
GET
use gostd:: net:: http:: async_http;
#[ async_std:: main]
async fn main ( ) -> anyhow:: Result < ( ) > {
let url = "https://petstore.swagger.io/v2/pet/findByStatus?status=available" ;
let response = async_http:: Get ( url) . await ?;
println ! (
"{}" ,
String :: from_utf8( response. Body . expect( "return body error" ) . to_vec( ) ) . unwrap( )
) ;
Ok ( ( ) )
}
或者
use gostd:: net:: http:: { async_http:: AsyncClient , Method , Request } ;
#[ async_std:: main]
async fn main ( ) -> anyhow:: Result < ( ) > {
let url = "https://petstore.swagger.io/v2/pet/findByStatus?status=available" ;
let mut req = Request :: New ( Method :: Get , url, None ) ?;
req. Header . Set ( "Content-Type" , "application/json" ) ;
let mut client = AsyncClient :: New ( ) ;
let response = client. Do ( & mut req) . await ?;
println ! (
"{}" ,
String :: from_utf8( response. Body . expect( "return body error" ) . to_vec( ) ) . unwrap( )
) ;
Ok ( ( ) )
}
Cargo.toml配置:
tokio = { version = "1.44", features = ["full"] }
gostd = { version = "0.4" ,features =["tokio-rt""]}
POST
use gostd:: net:: http:: async_http
#[ tokio:: main]
async fn main ( ) -> anyhow:: Result < ( ) > {
let url = "https://petstore.swagger.io/v2/pet" ;
let postbody = r#"{"id":0,"category":{"id":0,"name":"string"},"name":"doggie","photoUrls":["string"],"tags":[{"id":0,"name":"string"}],"status":"available"}"#
. as_bytes ( )
. to_vec ( ) ;
let response = async_http:: Post ( url, "application/json" , Some ( postbody. into ( ) ) ) . await ?;
println ! (
"{}" ,
String :: from_utf8( response. Body . expect( "return body error" ) . to_vec( ) ) . unwrap( )
) ;
Ok ( ( ) )
}
或者
use gostd:: net:: http:: { async_http:: AsyncClient , Method , Request } ;
#[ tokio:: main]
async fn main ( ) -> anyhow:: Result < ( ) > {
let url = "https://petstore.swagger.io/v2/pet" ;
let postbody = r#"{
"id": 0,
"category": {
"id": 0,
"name": "string"
},
"name": "doggie",
"photoUrls": [
"string"
],
"tags": [
{
"id": 0,
"name": "string"
}
],
"status": "available"
}"#
. as_bytes ( )
. to_vec ( ) ;
let mut req = Request :: New ( Method :: Post , url, Some ( postbody. into ( ) ) ) ?;
req. Header . Set ( "accept" , "application/json" ) ;
req. Header . Set ( "Content-Type", "application/json" ) ;
let mut client = AsyncClient :: New ( ) ;
let response = client. Do ( & mut req) . await ?;
println ! (
"{}" ,
String :: from_utf8( response. Body . expect( "return body error" ) . to_vec( ) ) . unwrap( )
) ;
Ok ( ( ) )
}
// output
// {"id":92233723685477587,"category":{"id":,"name":"string"},"name":"doggie","photoUrls":["string"],"tags":[{"id":,"name":"string"}],"status":"available"}
GET
use gostd:: net:: http:: async_http;
#[ tokio:: main]
async fn main ( ) -> anyhow:: Result < ( ) > {
let url = "https://petstore.swagger.io/v2/pet/findByStatus?status=available" ;
let response = async_http:: Get ( url) . await ?;
println ! (
"{}" ,
String :: from_utf8( response. Body . expect( "return body error" ) . to_vec( ) ) . unwrap( )
) ;
Ok ( ( ) )
}
或者
use gostd:: net:: http:: { async_http:: AsyncClient , Method , Request } ;
#[ tokio:: main]
async fn main ( ) -> anyhow:: Result < ( ) > {
let url = "https://petstore.swagger.io/v2/pet/findByStatus?status=available" ;
let mut req = Request :: New ( Method :: Get , url, None ) ?;
req. Header . Set ( "Content-Type" , "application/json" ) ;
let mut client = AsyncClient :: New ( ) ;
let response = client. Do ( & mut req) . await ?;
println ! (
"{}" ,
String :: from_utf8( response. Body . expect( "return body error" ) . to_vec( ) ) . unwrap( )
) ;
Ok ( ( ) )
}
POST
use gostd:: net:: http;
fn main ( ) -> anyhow:: Result < ( ) > {
let url = "https://petstore.swagger.io/v2/pet" ;
let postbody = r#"{"id":0,"category":{"id":0,"name":"string"},"name":"doggie","photoUrls":["string"],"tags":[{"id":0,"name":"string"}],"status":"available"}"#
. as_bytes ( )
. to_vec ( ) ;
let response = http:: Post ( url, "application/json" , Some ( postbody) ) ?;
println ! (
"{}" ,
String :: from_utf8( response. Body . expect( "return body error" ) ) . unwrap( )
) ;
Ok ( ( ) )
}
或者
use gostd:: net:: http:: { Client , Method , Request } ;
fn main ( ) -> anyhow:: Result < ( ) > {
let url = "https://petstore.swagger.io/v2/pet" ;
let postbody = r#"{
"id": 0,
"category": {
"id": 0,
"name": "string"
},
"name": "doggie",
"photoUrls": [
"string"
],
"tags": [
{
"id": 0,
"name": "string"
}
],
"status": "available"
}"#
. as_bytes ( )
. to_vec ( ) ;
let mut req = Request :: New ( Method :: Post , url, Some ( postbody) ) ?;
req. Header . Set ( "accept" , "application/json" ) ;
req. Header . Set ( "Content-Type" , "application/json" ) ;
let mut client = Client :: New ( ) ;
let response = client. Do ( & mut req) ?;
println ! (
"{}" ,
String :: from_utf8( response. Body . expect( "return body error" ) ) . unwrap( )
) ;
Ok ( ( ) )
}
// output
// {"id":92233723685477587,"category":{"id":,"name":"string"},"name":"doggie","photoUrls":["string"],"tags":[{"id":,"name":"string"}],"status":"available"}
GET
use gostd:: net:: http;
fn main ( ) -> anyhow:: Result < ( ) > {
let url = "https://petstore.swagger.io/v2/pet/findByStatus?status=available" ;
let response = http:: Get ( url) ?;
println ! (
"{}" ,
String :: from_utf8( response. Body . expect( "return body error" ) ) . unwrap( )
) ;
Ok ( ( ) )
}
或者
use gostd:: net:: http:: { Client , Method , Request } ;
fn main ( ) -> anyhow:: Result < ( ) > {
let url = "https://petstore.swagger.io/v2/pet/findByStatus?status=available" ;
let mut req = Request :: New ( Method :: Get , url, None ) ?;
req. Header . Set ( "Content-Type" , "application/json" ) ;
let mut client = Client :: New ( ) ;
let response = client. Do ( & mut req) ?;
println ! (
"{}" ,
String :: from_utf8( response. Body . expect( "return body error" ) ) . unwrap( )
) ;
Ok ( ( ) )
}
推荐配合 Rust 社区标准库 serde 和 serde_json 来处理结构化数据。
use gostd:: net:: http:: { Method , Request , AsyncClient } ;
use serde:: { Deserialize , Serialize } ;
#[ derive( Serialize , Deserialize , Debug ) ]
struct User {
id : u64 ,
name : String ,
}
#[ tokio:: main]
async fn main ( ) -> anyhow:: Result < ( ) > {
// 1. 序列化
let user = User { id : 1 , name : "Alice" . into ( ) } ;
let body = serde_json:: to_vec ( & user) ?;
// 2. 发送
let mut client = AsyncClient :: New ( ) ;
let mut req = Request :: New ( Method :: Post , "http://api.example.com/user" , Some ( body. into ( ) ) ) ?;
let response = client. Do ( & mut req) . await ?;
// 3. 反序列化响应
if let Some ( data) = response. Body {
let resp_user: User = serde_json:: from_slice ( & data) ?;
println ! ("Received: {:?}" , resp_user) ;
}
Ok ( ( ) )
}
字符串替换 strings::ReplaceAll()
use gostd:: strings;
fn main ( ) {
assert_eq ! (
"moo moo moo" ,
strings:: ReplaceAll ( "oink oink oink" , "oink" , "moo" )
) ;
}
字符串分割 strings::Split()
use gostd:: strings;
fn main ( ) {
assert_eq ! ( vec![ "a" , "b" , "c" ] , strings:: Split ( "a,b,c" , "," ) ) ;
assert_eq ! (
vec![ "" , "man " , "plan " , "canal panama" ] ,
strings:: Split ( "a man a plan a canal panama" , "a " )
) ;
assert_eq ! (
vec![ "" , " " , "x" , "y" , "z" , " " , "" ] ,
strings:: Split ( " xyz " , "" )
) ;
assert_eq ! ( vec![ "" ] , strings:: Split ( "" , "Bernardo O'Higgins" ) ) ;
}
字符串位置查找 strings::Index
use gostd:: strings;
fn main ( ) {
assert_eq ! ( 4 , strings:: Index ( "chicken" , "ken" ) ) ;
assert_eq ! ( -1 , strings:: Index ( "chicken" , "dmr" ) ) ;
}
将多个字符串连接成一个新字符串 strings::Join
use gostd:: strings;
fn main ( ) {
let s = vec ! [ "foo" , "bar" , "baz" ] ;
assert_eq ! ( "foo, bar, baz" , strings:: Join ( s, ", " ) ) ;
}
字符串转换成大写 strings::ToUpper
use gostd:: strings;
fn main ( ) {
assert_eq ! ( "GOPHER" , strings:: ToUpper ( "Gopher" ) ) ;
}
字符串转换成小写 strings::ToLower
use gostd:: strings;
fn main ( ) {
assert_eq ! ( "gopher" , strings:: ToLower ( "Gopher" ) ) ;
}