接受通用结构的函数

huangapple go评论95阅读模式
英文:

Function that accepts generic struct

问题

下面是你的翻译结果:

我的函数定义是否可以接受任何类型的结构体?

我尝试进行如下重构:

// 这个方法应该接受任何类型的结构体
// 一旦我从数据库接收到响应,
// 我会扫描行来创建一个结构体切片。

func generateResponse(rows *sqlx.Rows, structSlice []struct{}, structBody struct{}) ([]struct{}, error) {
for rows.Next() {

    err := rows.StructScan(&structBody)

    if err != nil {
        return nil, err
    }

    structSlice = append(structSlice, structBody)

}

err := rows.Err()
if err != nil {
    return nil, err
}

return structSlice, nil

}

假设我的结构体类型是 OrderRevenue

当我调用上面的函数时:

structSlice, err := generateResponse(rows, []OrderRevenue{}, OrderRevenue{})

我得到的错误是:

cannot use []OrderRevenue literal as type []struct{} in argument...

我这样做错了吗?

英文:

Is it possible to have my function definition below accept any type of struct?

I've tried to refactor like so:

// This method should accept any type of struct
// Once I receive my response from the database,
// I scan the rows to create a slice of type struct.

func generateResponse(rows *sqlx.Rows, structSlice []struct{}, structBody struct{}) ([]struct{}, error) {
	for rows.Next() {

		err := rows.StructScan(&structBody)

		if err != nil {
			return nil, err
		}

		structSlice = append(structSlice, structBody)

	}

	err := rows.Err()
	if err != nil {
		return nil, err
	}

	return structSlice, nil
}

Assume my struct is of type OrderRevenue.

When I call the function above:

structSlice, err := generateResponse(rows, []OrderRevenue{}, OrderRevenue{})

The error I get is:

cannot use []OrderRevenue literal as type []struct{} in argument...

Am I going about this the wrong way?

答案1

得分: 2

这被认为是Go类型系统的基石(或者更像是一种限制)。struct{}是一个无名类型,与struct{ field1 int }不同,当然也不同于OrderRevenue{}

Go通过接口强调抽象,也许你应该尝试一下这个。这是第一种方法:

type OrderRevenue interface {
    MarshalMyself() ([]byte, error)
}

type Anonymous struct{}
func (a Anonymous) MarshalMyself() ([]byte, error) {
    // 实现由你来完成
    return []byte{}, nil
}

// 函数签名
func generateResponse(rows *sqlx.Rows, structSlice []OrderRevenue, structBody Body) ([]Body, error) {
    // ...
}

在这种情况下,你也可以使用空接口interface{},它是所有类型都实现的,但你需要递归地遍历结构来进行手动类型断言。在Go中,最好提前知道数据的形状,至少部分地知道。

英文:

This is considered the cornerstone (or more of a limitation) of Go's type system. struct{} is an unnamed type that is different from struct{ field1 int } and of course is not the same as OrderRevenue{}.

Go emphasizes abstraction through interfaces, and perhaps you should try that. Here is the first take:

  type OrderRevenue interface {
          MarshalMyself() ([]byte, error)
  }

  type Anonymous struct {}
  func (a Anonymous) MarshalMyself() ([]byte, error) {
          // implementation's up to you
          return []byte{}, nil
  }

  // the function signature
  generateResponse(rows *sqlx.Rows, structSlice []OrderRevenue, structBody Body) ([]Body, error) {
          // ...
  }

In this case you can also use empty interface interface{}, which all types implement, but you'll have to recursively go through the structure to do manual type assertion. The best approach in Go is to know the shape of your data in advance, at least partially.

答案2

得分: 0

也许你可以使用反射来检查你的参数是否是一个结构体。

///一些代码	
v := reflect.TypeOf(structBody)
if v.Kind() != reflect.Struct {
    return nil, fmt.Errorf("参数不是一个结构体")
}
///一些代码

并且你可以使用泛型来指定参数的类型

```go
func generateResponse[t any](rows *sqlx.Rows, structSlice []t, structBody t) ([]t, error) {

    v := reflect.TypeOf(structBody)
    if v.Kind() != reflect.Struct {
        return nil, fmt.Errorf("参数不是一个结构体")
    }

    for rows.Next() {
       
        err := rows.StructScan(&structBody)

        if err != nil {
            return nil, err
        }

        structSlice = append(structSlice, structBody)

    }

    err := rows.Err()
    if err != nil {
        return nil, err
    }

    return structSlice, nil
}
英文:

maybe you can use the reflection to check whether your argument is a struct or not.

///some codes	
v := reflect.TypeOf(structBody)
if v.Kind() != reflect.Struct {
	return nil, fmt.Errorf("argument is not a struct")
}
///some codes

and you use generic to specify the types of your parameters

func generateResponse[t any](rows *sqlx.Rows, structSlice []t, structBody t) ([]t, error) {

 v := reflect.TypeOf(structBody)
 if v.Kind() != reflect.Struct {
	return nil, fmt.Errorf("argument is not a struct")
 }

for rows.Next() {
   
    err := rows.StructScan(&structBody)

    if err != nil {
        return nil, err
    }

    structSlice = append(structSlice, structBody)

}

err := rows.Err()
if err != nil {
    return nil, err
}

return structSlice, nil

}

huangapple
  • 本文由 发表于 2017年8月10日 01:00:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/45596651.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定