Go、Stripe、迭代器和抽象

kuhbmx9i  于 2023-09-28  发布在  Go
关注(0)|答案(3)|浏览(137)

我是戈朗的新手。我正在做一个项目,该项目涉及到stripe并提取不同stripe表(例如Product和Plan)的内容。最终,我将从Stripe的40-50个表中提取数据,所以我正在寻找保持数据保持稳定的方法。
目前,我有一些函数可以提取每个表所需的所有数据。基本上,每个表的函数都是相同的,不同之处在于构建迭代器和从特定表中获取数据。
这里是函数。为了清楚起见,我把所有与问题无关的东西都去掉了。

  1. func getAllCoupon(folderName string) {
  2. // do a bunch of setup stuff, init some vars, etc
  3. stripeIter := getCouponIter("")
  4. for okToContinue {
  5. lastId := ""
  6. for stripeIter.Next() && okToContinue {
  7. p := stripeIter.Coupon()
  8. // do some things with p
  9. }
  10. }
  11. if pageLineCount == 0 {
  12. okToContinue = false
  13. } else {
  14. stripeIter = getCouponIter(lastId)
  15. }
  16. }
  17. . . .
  18. }
  19. func getCouponIter(id string) *coupon.Iter {
  20. params := &stripe.CouponListParams{}
  21. params.Filters.AddFilter("limit", "", config.Config.Input.StripeMaxPageSize)
  22. if id != "" {
  23. params.Filters.AddFilter("starting_after", "", id)
  24. }
  25. return coupon.List(params)
  26. }

因此,与其有40-50个getAll()副本,我更希望有一个副本,并传入一个生成迭代器的函数-在本例中是getCouponIter。
我查看了stripe包代码,并尝试更改getAll函数签名以包含一个参数:

  1. func getAllCoupon(folderName string, getIter func(string) *stripe.Iter)

稍微调整一下,我就能把所有东西都调好。除了getCouponIter的返回类型。该函数的返回类型是*coupon.Iter的返回类型。
所以我很好奇如果我只想用一个GetAll函数结束,只传入一个查询stripe的函数,并传回一个迭代器,我应该怎么做?
编辑:hanzo正确地指出,这与条纹支付没有真正的关系,除了我必须使用他们的框架来迭代他们返回的数据。这与我如何以某种方式抽象迭代器有关,所以我没有40个相同函数的副本。
编辑:Burak塞尔达尔询问迭代器是否都具有相同的功能。问题是,我想把一个函数传递给getAll函数,它在需要时生成这些迭代器。迭代器是分页的(例如,对于事件),因此我可能需要在执行过程中重新生成迭代器。
因此,我有生成如下迭代器的函数:

  1. func getCouponIter(id string) *coupon.Iter
  2. func getCustomerIter(id string) *customer.Iter
  3. etc

我想将这些迭代器生成器函数中的一个传递给提取所有数据的函数。我遇到的问题是,要为它们定义一个接口,它们需要相同的返回类型(如果我错了,请告诉我),我不能强制它们返回任何不同于它们返回的东西。

vulvrdjw

vulvrdjw1#

当你需要复制/粘贴代码时,你可以使用泛型。
我相信stripe迭代器可以用以下方式表示:

  1. type StripeIter interface {
  2. Next() bool
  3. Current() interface
  4. }

使用这个,你可以创建一个泛型类型安全迭代器:

  1. type GenericIter[T any] struct {
  2. StripeIter
  3. }
  4. func (g *GenericIter[T]) Item() T {
  5. return g.Current().(T)
  6. }

然后,您可以将GetAll定义为:

  1. func getAll[T any](folderName string, get func() *GenericIter[T]) {
  2. iter:=get()
  3. // Iterate using iter and type T
  4. }

称之为:

  1. getAll[*stripe.Something](folder, &GenericIter{getSometing(id)})

其中getSomething返回一个Stripe迭代器。
可能有缺失的部分,但这应该给予你一个大致的概念。

展开查看全部
dphi5xsq

dphi5xsq2#

基于所有迭代器具有相同函数的事实,您可以创建一个封装这些函数的接口:

  1. type Iter interface {
  2. // iteration functions
  3. }

然后更新getAll的函数参数以返回该接口:

  1. func getAll(getIter func(string) Iter) {
  2. iter := getIter("some string")
  3. // do something with iter, create return data, paginate, etc.
  4. }

这样,无论您生成的是*coupon.Iter还是*customer.Iter,都可以使用相同的getAll函数。
同样,这是假设所有迭代都具有相同的函数(相同的名称,相同的类型)。

7y4bm7vi

7y4bm7vi3#

所以@Burak的泛型答案非常有用。我很难让它工作,所以我开始在条纹的代码中挖掘。
Stripe返回类型为 *customer.Iter或 *product.Iter的迭代器,但这些只是Stripe迭代器的 Package ,还有一些有用的附加内容:stripe.Iter.
因此,在上面的getCouponIter(string) *coupon.Iter代码中,我将返回值从:return coupon.List(params)

  1. tmp := coupon.List(params)
  2. return tmp.Iter

这返回 stripe.Iter,它们都共享它,所以现在所有getIter函数的签名都是相同的。
所以getAll的签名现在是:

  1. func getAll(folderName string, getIter func(string) *stripe.Iter)

这就是我需要的谢谢你@burak

相关问题