导入gust包体验Golang的声明式编程
开发者:https://github.com/andeya
作者:https://github.com/GpigZ
地址:https://github.com/andeya/gust
gust基本介绍
官方介绍
A Rust-inspired declarative programming module for Golang that helps reduce bugs and improve development efficiency. For example results, options, iterators, etc.
个人介绍
官方介绍解析
希望通过良好的编程规范或者说希望通过最大限度的利用编译器来解决运行时可能出现的bug。并且通过声明式编程来提高开发效率。
声明式编程
维基百科中:
声明式编程(英语:Declarative programming)或译为声明式编程,是对与命令式编程不同的编程范型的一种合称。它们建造计算机程序的结构和元素,表达计算的逻辑而不用描述它的控制流程。
常见的声明式语言包括:数据库查询语言如SQL的查询子集和XQuery(英语:XQuery),正则表达式,配置管理系统如Puppet管理配置语言。归入这种范型的很多语言,描述问题领域(英语:Domain knowledge)内目标的性质,让电脑明白目标,而非流程,从而尝试极小化有关的副作用。而命令式编程则需要用语言原语(英语:Language primitive)来明确的指出每一步该怎么做。
可归入声明式编程范型的领域专属语言(DSL)还包括:yacc语法解析器,编译说明语言Make等。DSL不需要是图灵完全的,往往容易以一种纯声明式的方式来表达。很多文本标记语言例如HTML、MXML、XAML和XSLT往往是声明式的。
声明式编程,通常被定义为除命令式以外的任何编程范型。同时存在一些其他的定义,简单的将声明式编程和命令式编程做对比,例如:
- 告诉计算机需要计算“什么”而不是“如何”去计算的高级程序。
- 明确的对应数理逻辑的编程语言(([4]))。
- 任何没有副作用的编程语言,或者更确切一点,任何参照透明(英语:referential transparency)的编程语言。
这些定义存在着一些重合。
体现gust中声明式编程的例子(部分内容,详细内容可在使用中体验)
判断数组中所有的值是否都小于等于1。
不使用gust
numbers := []int{1, 2, 3}
for _, v := range numbers {if v > 1 {return}
}
fmt.Println("all numbers less than or equal to 1")
使用gust
var iter = FromVec([]int{0, 1})
if !iter.Any(func(x int) bool {return x > 1
}) {fmt.Println("all numbers less than or equal to 1")
}
把数组中与2求余不等于0的数放入result
不使用gust
array := []int{0, 1, 2, 3}
var result []int
for _, num := range array {if num%2 != 0 {result = append(result, num)}
}
使用gust
var iter = FromVec([]int{0, 1, 2, 3})
var results []int
iter.Inspect(func(num int) {if num%2 != 0 {results = append(results, num)}
}).Collect()
把数组中所有数乘以2
不使用gust
array := []int{1, 2, 3}
for i, _ := range array {array[i] = 2 * array[i]
}
使用gust
array := FromVec([]int{1, 2, 3, 4}).
var result = array.Map(func(x int) any { return 2 * x }).Collect()
gust体现易用性和安全性的例子(部分内容,详细内容可在使用中体验)
- 我们需要处理strconv中返回value和err,并且err为空的时候值也有可能为空的时候。
var okStr = "20"var errStr = "not a number"var emptyStr string// Ret encapsulates value and err into resultokResult := gust.Ret(strconv.ParseUint(okStr, 10, 64))errResult := gust.Ret(strconv.ParseUint(errStr, 10, 64))emptyResult := gust.Ret(strconv.ParseUint(emptyStr, 10, 64))assert.Equal(t, uint64(20), okResult.Unwrap())assert.Equal(t, true, errResult.IsErr())assert.Equal(t, true, emptyResult.IsErr())// If an error occurs Ok will set it to empty// If you encounter the return value is empty but err is also empty, You can use ok to convert result to optionokOption := okResult.Ok()errOption := errResult.Ok()emptyOption := emptyResult.Ok()assert.Equal(t, uint64(20), okOption.Unwrap())assert.Equal(t, true, errOption.IsNone())assert.Equal(t, true, emptyOption.IsNone())
我们可以使用result接收value和err,然后把result转换成option进行非空判断。这样可以更便捷的处理value和err,并且在err为空和值同时为空的时候gust会自动帮我们声明值,避免直接调用值导致的空指针panic。
- 以下是体现其易用性的例子。当struct中属性可能为空的时候。
type SearchUserReq struct {Type gust.Option[string]Name gust.Option[string]Email gust.Option[string]
}
func (dao Dao) SearchUser(c context.Context, req SearchUserReq) gust.Result[Data]{var db = dao.WithDB(c)req.Type.Inspect(func(v string) {db = db.Where("type=?", v)})req.Name.Inspect(func(v string) {db = db.Where("type=?", v)})req.Email.Inspect(func(v string) {db = db.Where("type=?", v)})var r Dataerr :=db.Find(&r).Errorreturn gust.Ret(r,err)
}
使用Option表达 struct 字段可选,有效区分 零值和空值,比用 *T 的方式要更加安全,语义也更明确,且提供了丰富的类型方法,快捷满足各自处理逻辑。
gust内容展示(部分内容,详细内容可在使用中体验)
Option
struct:
// Option can be used to avoid `(T, bool)` and `if *U != nil`, // represents an optional value: // // every [`Option`] is either [`Some`](which is non-none T), or [`None`](which is none). type Option[T any] struct {value *T }
use:
如果为空执行默认func否则执行目标func
var k = 21 {var x = gust.Some("foo")assert.Equal(t, 3, x.XMapOrElse(func() any { return 2 * k }, func(v string) any { return len(v) })) } {var x gust.Option[string]assert.Equal(t, 42, x.XMapOrElse(func() any { return 2 * k }, func(v string) any { return len(v) })) }
Result
struct:
// Result can be used to improve `func()(T,error)`, // represents either success (T) or failure (error). type Result[T any] struct {inner EnumResult[T, error] } // EnumResult represents a success (T) or failure (E) enumeration. type EnumResult[T any, E any] struct {val anyisErr bool }
use:
在对错误值进行Map处理时会跳过,避免对错误值进行运算从而导致发生未知的bug,并且提供了丰富的类型方法。
var goodResult1 = gust.Ok(10) var badResult1 = gust.Err[int](10) // The `IsOk` and `IsErr` methods do what they say. assert.True(t, goodResult1.IsOk() && !goodResult1.IsErr()) assert.True(t, badResult1.IsErr() && !badResult1.IsOk()) // `map` consumes the `Result` and produces another. var goodResult2 = goodResult1.Map(func(i int) int { return i + 1 }) var badResult2 = badResult1.Map(func(i int) int { return i - 1 }) // Use `AndThen` to continue the computation. var goodResult3 = ret.AndThen(goodResult2, func(i int) gust.Result[bool] { return gust.Ok(i == 11) }) // Use `OrElse` to handle the error. var _ = badResult2.OrElse(func(err error) gust.Result[int] {fmt.Println(err)return gust.Ok(20) }) // Consume the result and return the contents with `Unwrap`. var _ = goodResult3.Unwrap()
EnumResult(自定义Result)
struct:
// EnumResult represents a success (T) or failure (E) enumeration. type EnumResult[T any, E any] struct {val anyisErr bool }
use:
EnumResult.IsErrrAnd判断EnumResult[T any, E any]范型E中是否有值,如果有值对值的内容进行回调函数中的判断返回相应的bool,没有值则返回false。
var x = gust.EnumErr[int, int8](-1) assert.True(t, x.IsErrAnd(func(x int8) bool { return x == -1 }))
Errable
struct:
type Errable[T any] struct {errVal *T }
use:
我们使用自定义错误的时候。尽管我们写入的参数4是符合预期的,但是因为在error封装了一层自定义实现错误,error是interface类型,在interface中只有类型和值均为空才是nil,所以在Bar返回的err!=nil但是预期上err应该为空,使用errable可以避免这个问题。
var _ error = new(MyError) type MyError struct {val string } func (m *MyError) Error() string {return m.val } func Foo(n int) *MyError {if n%2 == 0 {return nil}return &MyError{val: "bad",} } // Use errable to avoid err not being empty func Foo2(n int) gust.Errable[string] {if n%2 == 0 {return gust.NonErrable[string]()}return gust.ToErrable[string]("bad") } func Bar2(n int) error {return Foo2(n).ToError() } func Bar(n int) error {return Foo(n) } func TestErrableExample(t *testing.T) {err := Bar(4)if err != nil {fmt.Println("i have error")}err = Bar2(4)assert.Equal(t, nil, err) }
Iterator
struct:
type Iterator[T any] interface {Next() gust.Option[T]NextChunk(n uint) ([]T, bool)SizeHint() (uint, gust.Option[uint])Count() uintFold(init any, fold func(any, T) any) anyTryFold(init any, fold func(any, T) gust.Result[any]) gust.Result[any]Last() gust.Option[T]AdvanceBy(n uint) gust.Errable[uint]Nth(n uint) gust.Option[T]ForEach(f func(T))Reduce(f func(accum T, item T) T) gust.Option[T]All(predicate func(T) bool) boolAny(predicate func(T) bool) bool .Find(predicate func(T) bool) gust.Option[T]FindMap(f func(T) gust.Option[any]) gust.Option[any]TryFind(predicate func(T) gust.Result[bool]) gust.Result[gust.Option[T]]Position(predicate func(T) bool) gust.Option[int]StepBy(step uint) *StepByIterator[T]Filter(f func(T) bool) *FilterIterator[T]FilterMap(f func(T) gust.Option[T]) *FilterMapIterator[T]Chain(other Iterator[T]) *ChainIterator[T]Map(f func(T) any) *MapIterator[T, any]Inspect(f func(T)) *InspectIterator[T]Fuse() *FuseIterator[T]Collect() []T
use:
使用Any来遍历一组数据,并且对其中的值进行判断
var iter = FromVec([]int{1, 2, 3}) if !iter.Any(func(x int) bool {return x > 1 }) {t.Error("Any failed")}
初心与展望
我们希望我们的编程变得更加的便捷,我们希望我们在编程的时候只需要关注于我们的目标结果而不是里面的各种细节。并且我们希望我们的代码可以在编译期就发现问题的所在,而不在运行的时候才发现问题。在使用gust的时候如果你的代码编写得不那么符合规范的时候,它会在编译期就发现你的错误,我希望代码只要编译通过了,逻辑上没有问题,他就是没有bug的或者说是几乎没有bug。而且你的代码会变得更加的美观。这将让我们代码的维护成本降低,
我们希望它可以给大家带来更好的编程体验,所以有什么让你使用得不那么舒服的地方,我们希望你可以马上提出来,每个人宝贵的意见都会被我们看到,都会成为我们进步的助力。而且你在使用过程中发现了我们没有罗列出来的让你感到有趣的亮点,你也可以与我们分享与大家分享。我们希望编程不仅仅是人机交流,也是人与人之间的交流,思想是流动在人与人之间的。每个人的创造力都是伟大的,只是它可能没有被发现。
接口文档:https://pkg.go.dev/github.com/andeya/gust
导入gust包体验Golang的声明式编程相关推荐
- golang导入git包_使用go module导入本地包的方法教程详解
go module 是Go1.11版本之后官方推出的版本管理工具,并且从 Go1.13 版本开始, go module 将是Go语言默认的依赖管理工具.到今天 Go1.14 版本推出之后 Go mod ...
- go语言导入git包_使用go module导入本地包的方法教程详解
go module 是Go1.11版本之后官方推出的版本管理工具,并且从 Go1.13 版本开始, go module 将是Go语言默认的依赖管理工具.到今天 Go1.14 版本推出之后 Go mod ...
- go语言导入自定义包出现: package xxx is not in GOROOT (/xxx/xxx) 的解决方案
go语言导入自定义包出现: package xxx is not in GOROOT (/xxx/xxx) 的解决方案 1.问题 写了个自定义的包 calc.go,在路径 $GOPATH/projec ...
- Goland导入github包
goland终端如何导入github上的包 例如:我们要导入gin包,最开始我直接输入go get -u github.com/gin-gonic/gin 会出现以下的问题: # cd F:\gowo ...
- Unity 3D 导入资源包 || Unity 3D 导出资源包
项目中的一些资源具有复用性,只需要将资源导出,就能够重复使用. 导出资源包 执行 Assets → Select Dependencies 菜单命令,选中与导出资源相关的内容.接着执行 Assets→ ...
- Android studio 自动导入(全部)包 import
1 Android studio 只有import单个包的快捷键:Alt+Enter.没有Eclipse下的快速导入包的快捷键Ctrl+Shift+O. 2 但android studio设置里有一 ...
- 学生管理系统(用maven来导入jar包)
不废话,直接上 先看一下项目列表: 首先创建一个maven工程,然后导入相应的jar包,请参考:使用maven导入jar包 接着在Source Folder创建具体的项目: Main类(客户端) pa ...
- 使用maven导入jar包
我们都经历过自己写代码时有时就要引用一些第三方的jar包,这个我们都会,但在公司里进行团队开发时,是不允许我们自己导入jar包的,是由项目组长之类的统一导入jar包,我们在这里来了解一下这个过程: a ...
- python导入外部包_您会喜欢的10个外部Python软件包
python导入外部包 by Adam Goldschmidt 亚当·戈德施密特(Adam Goldschmidt) 您会喜欢的10个外部Python软件包 (10 External Python p ...
最新文章
- R语言使用ggplot2包使用geom_boxplot函数绘制基础分组箱图(分组箱体框颜色配置)实战
- iphone屏幕录制_如何将iPhone投屏到Mac上?iphone投屏到苹果电脑方法
- 2015年第六届蓝桥杯 - 省赛 - Java大学B组 - A. 三角形面积
- HTMLCSS课堂笔记
- matlab支持向量机程序代做
- OpenResty 安装,收集日志保存到文本文件
- 如何画圆柱_什么是最速降线?如何来验证一下呢?这里用SolidWorks来试一试
- 理解Linux的overcommit memory
- Beta版本冲刺———第二天
- Linux基础——Linux 基本指令 touch, cp 和 mv
- python在线学习直播-马哥教育官网-专业Linux培训班,Python培训机构
- ajax请求中带判断语句例子,jQuery中借助deferred来请求及判断AJAX加载的实例讲解...
- 华为防火墙管理员角色和级别详解
- selenium IDE下载及使用
- centos7构建kylo-0.10.1
- 微信开发 完美微信自动转发朋友圈-flutterAndroid
- 文本数据挖掘之文本信息抽取
- 查看jvm的运行参数
- 你知道数据运营日常主要工作吗?
- python中的self到底是什么