将自定义类型作为参数传递给函数

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

Custom type passed to function as a parameter

问题

当我定义一个自定义类型时,似乎底层类型的不同会影响我是否可以直接将其传递给函数,还是需要进行转换。

问题是:
为什么 RuneFuncStringMap 能够正常工作,但 Integer 不能?

链接:https://play.golang.org/p/buKNkrg5y-

package main

type RuneFunc func(rune) rune
type Integer int
type StringMap map[string]string

func main() {
    //m := make(StringMap)
    //mf(m)

    var i Integer = 5
    nf(i)

    //var f func(rune) rune
    //ff(f) 
}

func mf(i map[string]string) {

}

func ff(i func(rune) rune) {

}

func nf(i int) {

}

在这里,当我使用 Integer 调用名为 nf 的函数时,它会报错,尽管 int 是其底层类型。但是当我调用 mfff 时,它们可以成功运行。

英文:

When I define a custom type, it seems that the type of the underlying type makes a difference about whether I can pass it to a function as is or I need to convert it.

Question is:
Why does RuneFunc and StringMap work, but not Integer?

https://play.golang.org/p/buKNkrg5y-

package main


type RuneFunc func(rune) rune
type Integer int
type StringMap map[string]string

func main() {
    //m := make(StringMap)
    //mf(m)


    var i Integer = 5
    nf(i)


    //var f func(rune) rune
    //ff(f) 

}

func mf(i map[string]string) {

}
func ff(i func(rune)rune) {

}
func nf(i int) {

}

Here, when I run this function called nf with Integer it complains although int is the underlying type. But when I call mf or ff they run successfully.

答案1

得分: 22

Integerint

int和你的新类型Integer是两种不同的类型。在需要Integer类型的地方,你必须传递一个Integer类型的值。

如果你有一个Integer值,你可以使用简单的类型转换将其转换为int类型的值,因为Integer的底层类型是int

var i Integer = 5
nf(int(i))

可能令人困惑和有趣的是,你可以在不进行转换的情况下传递一个无类型常量:

nf(5)

Go Playground上尝试一下。

这是因为在规范: 可赋值性中有这样的规定:

x可以在以下任何情况下赋值给类型T变量("x可以赋值给T"):

[...]

  • x是一个无类型的常量,可以用类型T的值表示。

5是一个无类型常量,它的默认类型是int,所以它可以用Integer类型的值表示(因为Integer的默认类型也是int)。

如果你检查其他的可赋值性规则(不包括在上面的引述中),没有一个规则适用于你试图将Integer类型的值传递给int类型的参数,所以这是不允许的。

相关问题请参考:https://stackoverflow.com/questions/37385007/golang-creating-a-constant-type-and-restricting-the-types-values/37386119#37386119

RuneFuncfunc(rune) rune

这种情况与前面的情况(Integerint)的不同之处在于,int是一个命名类型,而func(rune) rune不是。

并且有一个可赋值性规则允许这样做:

所以在这种情况下:

var f RuneFunc
ff(f)

f是一个命名类型,但是ff()的参数类型是func(rune) rune,它是一个无名类型,所以赋值是允许的。

英文:

Integer and int

int and your new type Integer are 2 different, distinct types. Where Integer is expected, you have to pass a value of type Integer.

If you have an Integer value, you may use a simple type conversion to make it a value of type int, because the underlying type of Integer is int:

var i Integer = 5
nf(int(i))

What may be confusing and interesting at the same time is that you are allowed to pass an untyped constant without conversion:

nf(5)

Try these on the Go Playground.

The reason for this is in the Spec: Assignability:

> A value x is assignable to a variable of type T ("x is assignable to T") in any of these cases:

> [...]

> - x is an untyped constant representable by a value of type T.

5 is an untyped constant which is representable by a value of type int because the untyped constant 5 has a default type int, so it is representable by a value of type Integer (which has the same default type).

If you check the other assignability rules (not included in above quotation), none of them match the case where you attempt to pass a value of Integer for the parameter of type int, so that's not allowed.

See related question: https://stackoverflow.com/questions/37385007/golang-creating-a-constant-type-and-restricting-the-types-values/37386119#37386119

RuneFunc and func(rune) rune

The difference between this case and the previous one (Integer and int) is that int is a named type and func(rune) rune is not.

And there's an assignability rule which allows this:

> - x's type V and T have identical underlying types and at least one of V or T is not a named type.

So in this case:

var f RuneFunc
ff(f)

f is a named type, but the parameter type of ff() is func(rune) rune which is unnamed, so the assignment is allowed.

答案2

得分: 1

Go语言有严格的类型系统。仅仅因为你的类型只是int的别名,并不意味着你可以自由地互换它们,你仍然需要进行类型转换。下面是一个可工作的main函数版本,这是在playground上的代码链接:https://play.golang.org/p/BDTXnnG9Lg

英文:

Go has a strict type system. Just because your type is merely an alias for int doesn't mean you can interchange the two freely, you'll still have to do a type conversion. Below is a working version of your main, here's the code on play ground: https://play.golang.org/p/BDTXnnG9Lg

huangapple
  • 本文由 发表于 2017年1月6日 16:16:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/41501596.html
匿名

发表评论

匿名网友

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

确定