英文:
Generic Functions in Go
问题
我正在学习Go语言,文档和交互式课程中说,一个空的接口(empty interface)可以持有任何类型,因为它不需要额外实现的方法。
所以举个例子:
func describe(i interface{}) {
fmt.Printf("Type: %T | Value: %v\n", i, i)
}
...会输出...
"Type: int | Value: 5" // 当 i := 5
"Type: string | Value: test" // 当 i := "test"
...等等
所以我的问题是,这是Go语言实现泛型函数的方式吗?还是还有其他更合适的方式?
英文:
I'm in the process of learning Go
and the documentation and interactive lessons say that an empty interface
can hold any type, as it requires no additionally implemented methods.
So for an example:
func describe(i interface{}) {
fmt.Printf("Type: %T | Value: %v\n", i, i)
}
...would print out...
"Type: int | Value: 5" // for i := 5
"Type: string | Value: test" // for i := "test"
... etc
So I guess my question is if this is Go's
way of implementing generic functions or if there is another, more suitable, way of doing them.
答案1
得分: 24
从Go 1.18开始,你可以按照下面的方式编写一个通用函数Print
:
package main
import (
"fmt"
)
// T可以是任意类型
func Print[T any](s []T) {
for _, v := range s {
fmt.Print(v)
}
}
func main() {
// 传递字符串列表也可以工作
Print([]string{"Hello, ", "world\n"})
// 你也可以将整数列表传递给同一个函数
Print([]int{1, 2})
}
输出结果:
Hello, world
12
更多信息请参考:1: https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md
英文:
As of Go 1.18 you can write a generic function Print
as below:
package main
import (
"fmt"
)
// T can be any type
func Print[T any](s []T) {
for _, v := range s {
fmt.Print(v)
}
}
func main() {
// Passing list of string works
Print([]string{"Hello, ", "world\n"})
// You can pass a list of int to the same function as well
Print([]int{1, 2})
}
Output:
Hello, world
12
答案2
得分: 15
Go语言的范式通常是通过在非空接口中实现行为来避免这种情况。例如,假设你想要使用特定类型的格式打印某些内容:
func Print(i interface{}) {
switch o := i.(type) {
case int64:
fmt.Printf("%5d\n", o)
case float64:
fmt.Printf("%7.3f\n", o)
case string:
fmt.Printf("%s\n", o)
default: // 包括结构体等其他类型
fmt.Printf("%+v\n", o)
}
}
或者,你可以为那些知道如何将自己转换为字符串的对象定义一个接口(在基础库中作为fmt.Stringer
存在),然后使用该接口:
type Stringer interface {
String() string
}
func Print(o Stringer) {
fmt.Println(o.String())
}
type Foo struct {
a, b int
}
func (f Foo) String() string {
// 让我们使用一个与%+v不同的自定义输出格式
return fmt.Sprintf("%d(%d)", f.a, f.b)
}
type Bar struct {
t bool
}
func (b Bar) String() string {
if b.t {
return "TRUE! =D"
}
return "false =("
}
这样你就可以拥有类似泛型的功能,但仍保留类型安全性,并且行为本身由类型定义,而不是由你的通用函数定义。
Go鼓励你根据类型的行为来思考,它们能做什么,而不是它们包含了什么。
英文:
The Go paradigm is generally to avoid this by implementing the behavior in non-empty interfaces. For example, say you wanted to print something with type-specific formatting:
func Print(i interface{}) {
switch o := i.(type) {
case int64:
fmt.Printf("%5d\n", o)
case float64:
fmt.Printf("%7.3f\n", o)
case string:
fmt.Printf("%s\n", o)
default: // covers structs and such
fmt.Printf("%+v\n", o)
}
}
Alternatively, you could define an interface for things that know how to string themselves (this exists in the base library as an fmt.Stringer
), and use that:
type Stringer interface {
String() string
}
func Print(o Stringer) {
fmt.Println(o.String())
}
type Foo struct {
a, b int
}
func (f Foo) String() string {
// Let's use a custom output format that differs from %+v
return fmt.Sprintf("%d(%d)", f.a, f.b)
}
type Bar struct {
t bool
}
func (b Bar) String() string {
if b.t {
return "TRUE! =D"
}
return "false =("
}
https://play.golang.org/p/Ez6Hez6cAv
This lets you have a generic-like functionality, but still retain type safety and have the behavior itself defined by the types, rather than your generic function.
Go encourages you to think of types in this way, based on their behavior, what they can do rather than what they contain.
答案3
得分: 1
Golang没有泛型类型,所以解决这个问题的方法是传递interface
类型,并在函数内部使用类型断言。
英文:
Golang doesn't have a generic type, so the way you get around this is passing interface
type and using type switches within the function.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论