热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

导入gust包体验Golang的声明式编程

开发者:github.comandeya本文作者:github.comGpigZ地址:github.comandeyagustgust基本介绍官方介绍ARust-inspiredd






开发者:github.com/andeya

本文作者:github.com/GpigZ


地址: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. 判断数组中所有的值是否都小于等于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")
}


  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()


  1. 把数组中所有数乘以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 result
    okResult := 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 option
    okOption := 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 Data
    err :=db.Find(&r).Error
    return gust.Ret(r,err)
    }

使用Option表达 struct 字段可选,有效区分 零值和空值,比用 *T 的方式要更加安全,语义也更明确,且提供了丰富的类型方法,快捷满足各自处理逻辑。


gust内容展示(部分内容,详细内容可在使用中体验)



  1. 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) }))
    }

  2. 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 any
    isErr 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()

  3. EnumResult(自定义Result)

    struct:

    // EnumResult represents a success (T) or failure (E) enumeration.
    type EnumResult[T any, E any] struct {
    val any
    isErr 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 }))

  4. 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)
    }

  5. Iterator

    struct:(部分接口)


    Next() gust.Option[T]
    NextChunk(n uint) ([]T, bool)
    SizeHint() (uint, gust.Option[uint])
    Count() uint
    Fold(init any, fold func(any, T) any) any
    TryFold(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) bool
    Any(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。而且你的代码会变得更加的美观。这将让我们代码的维护成本降低,

我们希望它可以给大家带来更好的编程体验,所以有什么让你使用得不那么舒服的地方,我们希望你可以马上提出来,每个人宝贵的意见都会被我们看到,都会成为我们进步的助力。而且你在使用过程中发现了我们没有罗列出来的让你感到有趣的亮点,你也可以与我们分享与大家分享。我们希望编程不仅仅是人机交流,也是人与人之间的交流,思想是流动在人与人之间的。每个人的创造力都是伟大的,只是它可能没有被发现。


接口文档:pkg.go.dev/github.com/andeya/gust




推荐阅读
  • Android实战——jsoup实现网络爬虫,糗事百科项目的起步
    本文介绍了Android实战中使用jsoup实现网络爬虫的方法,以糗事百科项目为例。对于初学者来说,数据源的缺乏是做项目的最大烦恼之一。本文讲述了如何使用网络爬虫获取数据,并以糗事百科作为练手项目。同时,提到了使用jsoup需要结合前端基础知识,以及如果学过JS的话可以更轻松地使用该框架。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • Java和JavaScript是什么关系?java跟javaScript都是编程语言,只是java跟javaScript没有什么太大关系,一个是脚本语言(前端语言),一个是面向对象 ... [详细]
  • 本文介绍了2015年九月八日的js学习总结及相关知识点,包括参考书《javaScript Dom编程的艺术》、js简史、Dom、DHTML、解释型程序设计和编译型程序设计等内容。同时还提到了最佳实践是将标签放到HTML文档的最后,并且对语句和注释的使用进行了说明。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • 本文介绍了Python字典视图对象的示例和用法。通过对示例代码的解释,展示了字典视图对象的基本操作和特点。字典视图对象可以通过迭代或转换为列表来获取字典的键或值。同时,字典视图对象也是动态的,可以反映字典的变化。通过学习字典视图对象的用法,可以更好地理解和处理字典数据。 ... [详细]
  • 本文比较了eBPF和WebAssembly作为云原生VM的特点和应用领域。eBPF作为运行在Linux内核中的轻量级代码执行沙箱,适用于网络或安全相关的任务;而WebAssembly作为图灵完备的语言,在商业应用中具有优势。同时,介绍了WebAssembly在Linux内核中运行的尝试以及基于LLVM的云原生WebAssembly编译器WasmEdge Runtime的案例,展示了WebAssembly作为原生应用程序的潜力。 ... [详细]
  • 本文介绍了brain的意思、读音、翻译、用法、发音、词组、同反义词等内容,以及脑新东方在线英语词典的相关信息。还包括了brain的词汇搭配、形容词和名词的用法,以及与brain相关的短语和词组。此外,还介绍了与brain相关的医学术语和智囊团等相关内容。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 如何实现JDK版本的切换功能,解决开发环境冲突问题
    本文介绍了在开发过程中遇到JDK版本冲突的情况,以及如何通过修改环境变量实现JDK版本的切换功能,解决开发环境冲突的问题。通过合理的切换环境,可以更好地进行项目开发。同时,提醒读者注意不仅限于1.7和1.8版本的转换,还要适应不同项目和个人开发习惯的需求。 ... [详细]
  • 恶意软件分析的最佳编程语言及其应用
    本文介绍了学习恶意软件分析和逆向工程领域时最适合的编程语言,并重点讨论了Python的优点。Python是一种解释型、多用途的语言,具有可读性高、可快速开发、易于学习的特点。作者分享了在本地恶意软件分析中使用Python的经验,包括快速复制恶意软件组件以更好地理解其工作。此外,作者还提到了Python的跨平台优势,使得在不同操作系统上运行代码变得更加方便。 ... [详细]
  • Hibernate延迟加载深入分析-集合属性的延迟加载策略
    本文深入分析了Hibernate延迟加载的机制,特别是集合属性的延迟加载策略。通过延迟加载,可以降低系统的内存开销,提高Hibernate的运行性能。对于集合属性,推荐使用延迟加载策略,即在系统需要使用集合属性时才从数据库装载关联的数据,避免一次加载所有集合属性导致性能下降。 ... [详细]
  • 本文介绍了JavaScript进化到TypeScript的历史和背景,解释了TypeScript相对于JavaScript的优势和特点。作者分享了自己对TypeScript的观察和认识,并提到了在项目开发中使用TypeScript的好处。最后,作者表示对TypeScript进行尝试和探索的态度。 ... [详细]
author-avatar
江湖小子的美好生活_498_416
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有