任何/接口{}作为约束与参数类型之间的区别?

发布于 2025-01-30 00:59:27 字数 911 浏览 2 评论 0原文

由于仿制药已经在Go 1.18中发布了,因此我已经开始学习它们。我通常会得到这个概念,因为我过去有一些Java经验。但是我没有得到一些实施细节。

例如:当更合适地使用任何而不是接口{}时?这是一个示例:

func printInterface(foo interface{}) {
    fmt.Printf("%v\n", foo)
}

func printAny[T any](foo T) {
    fmt.Printf("%v\n", foo)
}

func (suite *TestSuite) TestString() {
    printInterface("foo")
    printAny("foo")
}

两个实现都起作用。但是,如果我尝试用任何 version打印nil,我将获得一个编译时错误:

不能推断t。

https://go.dev/play/pplay/p/0gmu4rhhaop

我赢了如果我尝试使用nil使用接口{} -version打印nil,请获取此错误。

那么任何的用例是什么?与简单地使用接口{}相比,它带来了何时以及哪些好处?

我要求提供一个特定的示例,其中一种实现比另一个实现更合适和/或可以评估的特定受益。

As generics have been released in Go 1.18 pretty recently, I've started learning them. I generally get the concept, because I have some Java experience from the past. But I don't get some implementation specifics.

For instance: when it's more suitable to use any instead of interface{}? Here's an example:

func printInterface(foo interface{}) {
    fmt.Printf("%v\n", foo)
}

func printAny[T any](foo T) {
    fmt.Printf("%v\n", foo)
}

func (suite *TestSuite) TestString() {
    printInterface("foo")
    printAny("foo")
}

Both implementations work. However, if I try to print nil with any-version, I'll get a compile-time error:

cannot infer T.

https://go.dev/play/p/0gmU4rhhaOP

And I won't get this error if I try to print nil with interface{}-version.

So what's the use-case for any? When and which benefits does it bring, compared to simply using interface{}?

I'm asking to provide a specific example, where one implementation is objectively more suitable than another and/or where there is a specific benefit that can be evaluated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

风追烟花雨 2025-02-06 00:59:28

任何别名 for interface {}}spec:接口类型:

为方便起见,预定类型任何都是空接口的别名。

由于它是一个别名,因此您使用哪一个都没关系。他们是一个又一个。它们是可以互换的。您可以用另一个替换一个,代码将表示相同。

任何较短,更清晰,但仅从GO 1.18起。

由于它们是可互换的,因此这也有效:

func printInterface(foo any) {
    fmt.Printf("%v\n", foo)
}

printany()不起作用的原因是它是具有类型参数的通用函数。要使用它,它必须为实例化(必须用已知类型分配其类型参数)。试图用nil调用它不会带来任何类型信息,因此不能发生实例化,类型推断将无法使用。

如果您使用nil值值,则可以使用类型信息,或者明确指定type param(在 go playground ):

printAny((*int)(nil))
printAny[*int](nil)
// Or
var r io.Reader
printAny(r)

正如所说,任何都可以与interface> interface {}互换,因此您'如果交换这两次出现,则LL具有相同的代码(在

func printInterface(foo any) {
    fmt.Printf("%v\n", foo)
}

func printAny[T interface{}](foo T) {
    fmt.Printf("%v\n", foo)
}

any is an alias for interface{}. Spec: Interface types:

For convenience, the predeclared type any is an alias for the empty interface.

Since it is an alias, it doesn't matter which one you use. They are one and the same. They are interchangeable. You can replace one with the other, the code will mean the same.

any is shorter and clearer, but only works from Go 1.18.

Since they are interchangeable, this also works:

func printInterface(foo any) {
    fmt.Printf("%v\n", foo)
}

The reason why printAny() doesn't work is due to it being a generic function with a type parameter. To use it, it must be instantiated (its type parameter must be assigned with a known type). Trying to call it with nil carries no type information, so instantiation cannot happen, type inference won't work.

If you call it with a nil value that carries type info, it'll work, or if you specify the type param explicitly (try it on the Go Playground):

printAny((*int)(nil))
printAny[*int](nil)
// Or
var r io.Reader
printAny(r)

And as said, any is interchangeable with interface{}, so you'll have the same code if you swap both occurrences (try this one on the Go Playground):

func printInterface(foo any) {
    fmt.Printf("%v\n", foo)
}

func printAny[T interface{}](foo T) {
    fmt.Printf("%v\n", foo)
}
野鹿林 2025-02-06 00:59:28

您的问题与的使用无关。如您所见,从这个游乐场,如果您使用explicit类型实例化函数,则代码> PRINTANY [ANY](NIL)它将起作用。

如果您具有具有通用类型的功能,则需要指定类型。但是,GO编译器非常聪明,可以为您推断某些类型。但是nil仅是无法推断的。

Your issue is not related to the usage of any/interface{} — whose difference is purely cosmetic — but it is type inference. As you can see from this playground, if you instantiate your function with an explicit type, like printAny[any](nil) it will work.

If you have a function with generic type you need to specify the types. However the go compiler is very smart and can infer some types for you. But nil alone is impossible to infer.

惯饮孤独 2025-02-06 00:59:27

除了其他任何和接口{}是类型别名 - 因此,在用法中等效 - 任何作为类型都有实际差异参数 如您的示例中的任何作为常规函数参数

区别在于,在printany [t any](foo t) foo的类型不是任何/接口>接口{} < /code>,但它是tt实例化是一种具体类型,它可能是接口本身也可能不是接口。然后,您只能将参数传递给可以分配给该混凝土类型的实例化printany

通过多个参数,这如何影响您的代码最为明显。如果我们稍微更改函数签名:

func printInterface(foo, bar any) {
    fmt.Println(foo, bar)
}

func printAny[T any](foo, bar T) {
    fmt.Println(foo, bar)
}

实例化后:

  • 函数printany接受相同类型的任何两个参数 - 以实例化t
  • printInterface,等效于printinterface(foo,bar Interface {})仍然可以接受两个不同类型的参数,因为两者都会是 个体可分配到任何/接口{}
printInterface(12.5, 0.1)    // ok
printInterface(12.5, "blah") // ok, int and string individually assignable to any

printAny(10, 20)             // ok, T inferred to int, 20 assignable to int
printAny(10, "k")            // compiler error, T inferred to int, "k" not assignable to int
printAny[any](10, "k")       // ok, T explicitly instantiated to any, int and string assignable to any

printAny(nil, nil)           // compiler error, no way to infer T
printAny[any](nil, nil)      // ok, T explicitly instantiated to any, nil assignable to any

一个游乐场: https://go.dev/play/pplay/pdjp986cj96

注释:不能使用nil在没有显式类型参数的情况下使用,仅仅是因为nil单独携带类型信息,因此编译器无法推断t。但是,nil通常可以分配给接口类型的变量。

Beside any and interface{} being type aliases — hence, equivalent in usage —, there is a practical difference between any as type parameter and any as regular function argument, as in your example.

The difference is that in printAny[T any](foo T) the type of foo is not any/interface{}, but it's T. And T after instantiation is a concrete type, that may or may not be an interface itself. You can then only pass arguments to an instantiated printAny that can be assigned to that concrete type.

How this impacts your code is most evident with multiple arguments. If we change the function signatures a bit:

func printInterface(foo, bar any) {
    fmt.Println(foo, bar)
}

func printAny[T any](foo, bar T) {
    fmt.Println(foo, bar)
}

After instantiation:

  • the function printAny accepts any two arguments of the same type — whichever is used to instantiate T
  • printInterface, which is equivalent to printInterface(foo, bar interface{}) can still accept two arguments of different types, since both would be individually assignable to any/interface{}.
printInterface(12.5, 0.1)    // ok
printInterface(12.5, "blah") // ok, int and string individually assignable to any

printAny(10, 20)             // ok, T inferred to int, 20 assignable to int
printAny(10, "k")            // compiler error, T inferred to int, "k" not assignable to int
printAny[any](10, "k")       // ok, T explicitly instantiated to any, int and string assignable to any

printAny(nil, nil)           // compiler error, no way to infer T
printAny[any](nil, nil)      // ok, T explicitly instantiated to any, nil assignable to any

A playground: https://go.dev/play/p/pDjP986cj96

Note: the generic version cannot be called with nil without explicit type arguments simply because nil alone doesn't carry type information, so the compiler can't infer T. However nil can be normally assigned to variables of interface type.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文