[转]在Go中实现自己的future语句

举报
Amrf 发表于 2021/06/20 20:32:31 2021/06/20
【摘要】 Go 编程语言的主要特点之一是它的同名go语句。不过,在我看来,该go声明也是其主要缺点之一。这不仅仅是我这么认为(https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/)。与表达式不同,语句不产生任何结果。在 Go 中,启动一个新的 goroutine 非常容易。...
type Future[type T] interface {
   Get() Result[T]
   Cancel()
}
type Result[type S] interface {
   Success() S
   Failure() error
}

为了支持 Result,我们需要一个结构来保存它的数据:

type result[type S] struct {
   success S
   failure error
}

查看结构,实现两个 Result 接口方法应该是微不足道的:

func (this *result(S)) Success() S {
   return this.success
}

func (this *result(S)) Failure() error {
   return this.failure
}
func (this *result(S)) String() string {
   if this.failure != nil {
      return fmt.Sprintf("%v", this.failure)
   } else {
      return fmt.Sprintf("%v", this.success)
   }
}

到目前为止,它应该非常简单。现在让我们讨论我们的结构支持Future将需要哪些数据。

有这个结构:

type future[type T] struct {
    ...
}
type future[type T] struct {
   result   *result[T]
   ...
}

了解 Future 是否已经完成也很有用:

type future[type T] struct {
   ...
   completed bool
   ...
}

如果它还没有完成,我们需要一种方法来等待它。Go 中的一种常见方法是使用通道:

type future[type T] struct { 
   ... 
   wait chan bool 
   ... 
}

我们的最后一个要求是能够取消Future. 为此,我们将使用Context, 返回一个我们需要调用以取消它的函数:

type future[type T] struct {
   ...
   cancel   func()
}

但参考Context自身也很有用:

type future[type T] struct {
   ...
   ctx      context.Context
   cancel   func()
}

就是这样,这就是我们Future现在需要的所有数据。

type future[type T] struct {
   result   *result[T]
   complete bool
   wait     chan bool
   ctx      context.Context
   cancel   func()
}

现在让我们实现这两种Future方法。

由于我们正在使用Context,取消我们Future变得微不足道:

func (this *future[T]) Cancel() {
   this.cancel()
}
func (this *future[T]) Get() Result[T] {
   if this.completed {
      return this.result
   } else {
      fmt.Println("Need to wait...")
      select {
      case <-this.wait:
         return this.result
      case <-this.ctx.Done():
         return &result(T){failure: this.ctx.Err()}
      }
   }
}
func NewFuture[type T](f func() (T, error)) Future[T] {
    ...
}
fut := &future[T]{
   wait: make(chan bool),
}
fut.ctx, fut.cancel = context.WithCancel(context.Background())
...

return fut
go func() {
   success, failure := f()

   fut.result = &result[T]{success, failure}
   fut.completed = true
   fut.wait <- true
   close(fut.wait)
}()
f1 := NewFuture(func() (string, error) {
   time.Sleep(1000)
   return "F1", nil
})

fmt.Printf("ready with %v \n", f1.Get()) 
// Need to wait...
// ready with F1
fmt.Printf("trying again with %v \n", f1.Get()) 
// trying again with F1
f2 := NewFuture(func() (string, error) {
   time.Sleep(1000)
   return "F2", fmt.Errorf("something went wrong")
})

fmt.Printf("ready with %v \n", f2.Get())
// Need to wait...
// ready with something went wrong
f3 := NewFuture(func() (string, error) {
   time.Sleep(100)
   fmt.Println("I'm done!")
   return "F3", nil
})
f3.Cancel()

fmt.Printf("ready with %v \n", f3.Get())
// Need to wait...
// ready with context canceled

结论

脚注

为什么golang下划线结构字段存在(https://paulyeo21.medium.com/golang-underscore-struct-field-f0aecabc72ae)

如果您编写了一些 go 或深入研究了一个维护良好的 go 项目,您可能会看到带有下划线字段的结构:

type ListTablesInput struct {
 _ struct{} `type:"structure"`
 ExclusiveStartTableName *string `min:"3" type:"string"
 Limit *int64 `min:"1" type:"integer"`
}

> https://github.com/aws/aws-sdk-go/blob/7e0246814d8eb87bdc6850c44e8f75f020db80eb/service/dynamodb/api.go#L15104-L15115

在结构上使用 _ 字段的目的是在初始化结构时强制使用键控字段。

input := ListTablesInput{
  ExclusiveStartTableName: "table-name",
  Limit: 100,
}
// instead of
input := ListTablesInput{"table-name", 100}

如果您尝试在没有字段名称的情况下初始化结构体,您将收到类似“不能在字段值中用作类型结构{}”这样的错误信息。

的enforcin的一大优势初始化结构时,这个规则是添加到任何结构新的领域将不引入重大更改。例如,添加了一个新字段,例如:

type ListTablesInput struct {
 _ struct{} `type:"structure"`
 ExclusiveStartTableName *string `min:"3" type:"string"`
 Limit *int64 `min:"1" type:"integer"`
  // New field
  Option string
}

那么从我们前面的例子来看,没有关键字段的结构初始化将无法编译,因为它现在需要添加新字段。

// valid still
ListTablesInput{
  ExclusiveStartTableName: "table-name",
  Limit: 100,
}
// fails to compile
ListTablesInput{"table-name", 100}
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。