在Go语言中的鸭子类型

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

Duck typing in Go

问题

[]myint无法传递给Join,因为它不是fmt.Stringer类型,所以我必须写成:

  1. parts := []fmt.Stringer{myint(1), myint(5), myint(6)}

但是如果我需要在另一个操作中使用parts,其中的值必须是整数,我应该将myint的切片转换为Stringer的切片吗?

英文:

I want to write a Join function that takes arbitrary objects with a String() method:

  1. package main
  2. import (
  3. "fmt"
  4. "strings"
  5. )
  6. type myint int
  7. func (i myint) String() string {
  8. return fmt.Sprintf("%d", i)
  9. }
  10. func main() {
  11. parts := []myint{myint(1), myint(5), myint(6)}
  12. fmt.Println(Join(parts, ", "))
  13. }
  14. func Join(parts []fmt.Stringer, sep string) string {
  15. stringParts := make([]string, len(parts))
  16. for i, part := range(parts) {
  17. stringParts [i] = part.String()
  18. }
  19. return strings.Join(stringParts , sep)
  20. }

http://play.golang.org/p/EhkbyibzHw

[]myint cannot be passed to Join, because it is not of type fmt.Stringer, so I have to write:

  1. parts := []fmt.Stringer{myint(1), myint(5), myint(6)}

But what if I need parts for another operation where the values have to be ints? Should I cast a slice of myint to a slice of Stringer then?

答案1

得分: 6

在Go语言中,没有强制类型转换,只有类型转换。但是,从具体的非接口类型的切片到接口类型的切片的转换是不可能的,除非在循环中显式地进行转换。原因是,例如在你的情况下,[]myint的底层数组与[]fmt.Stringer的内存布局不同。(相关FAQ)

另外,你不必写成:

  1. parts := []myint{myint(1), myint(5), myint(6)}

以下写法也可以:

  1. parts := []myint{1, 5, 6}
英文:

> Q: Should I cast a slice of myint to a slice of Stringer then?

There are no casts in Go - only conversions. But conversion from a slice of concrete, non interface type to a slice of interface type is not possible, except by doing it explicitly in a loop. The reason is that, as for example in your case, the []myint backing array has a different memory layout than []fmt.Stringer has. (Related FAQ)

On a side note, you don't have to write:

  1. parts := []myint{myint(1), myint(5), myint(6)}

This should work identically:

  1. parts := []myint{1, 5, 6}

答案2

得分: 1

将Join函数改为

  1. func Join(sep string, parts ...fmt.Stringer) string {
  2. }

会使得代码更加简洁:

  1. package main
  2. import (
  3. "fmt"
  4. "strings"
  5. )
  6. type myint int
  7. func (i myint) String() string {
  8. return fmt.Sprintf("%d", i)
  9. }
  10. type myfloat float32
  11. func (f myfloat) String() string {
  12. return fmt.Sprintf("%0.2f", f)
  13. }
  14. func main() {
  15. fmt.Println(Join(", ", myint(3), myfloat(3.5543)))
  16. }
  17. func Join(sep string, parts ...fmt.Stringer) string {
  18. stringParts := make([]string, len(parts))
  19. for i, part := range parts {
  20. stringParts[i] = part.String()
  21. }
  22. return strings.Join(stringParts, sep)
  23. }
英文:

Change the Join function to

  1. func Join(sep string, parts ...fmt.Stringer) string {
  2. }

makes it a lot easier:

  1. package main
  2. import (
  3. "fmt"
  4. "strings"
  5. )
  6. type myint int
  7. func (i myint) String() string {
  8. return fmt.Sprintf("%d", i)
  9. }
  10. type myfloat float32
  11. func (f myfloat) String() string {
  12. return fmt.Sprintf("%0.2f", f)
  13. }
  14. func main() {
  15. fmt.Println(Join(", ", myint(3), myfloat(3.5543)))
  16. }
  17. func Join(sep string, parts ...fmt.Stringer) string {
  18. stringParts := make([]string, len(parts))
  19. for i, part := range parts {
  20. stringParts[i] = part.String()
  21. }
  22. return strings.Join(stringParts, sep)
  23. }

huangapple
  • 本文由 发表于 2012年11月6日 19:16:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/13249843.html
匿名

发表评论

匿名网友

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

确定