Why does fmt.Printf accept a byte array for %x in Go

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

Why does fmt.Printf accept a byte array for %x in Go

问题

我对Go语言还不太熟悉。我想知道数组和切片之间的确切区别,请原谅我对规范过于执着。

fmt包的文档中,对于Printf函数,它说%x可以接受字符串和字节切片。但它没有提到字节数组。但实际上,如果我将一个字节数组放进去,它也可以正常打印出来!

package main

import (
  "fmt"
)

func main() {
  var b [6]byte
  for i := 0; i < 6; i++ {
    b[i] = 'a'
  }
  fmt.Printf("%s\n", b) // "aaaaaa"
}

有人能告诉我为什么吗?据我所知,字节数组和切片不能隐式地相互转换。

谢谢阅读我的问题!

英文:

I'm pretty new to Go. I want to know the exact difference between arrays and slices so please forgive me if I'm too obsessive over the spec.

In documentation for package fmt, it says for Printf that %x can accept strings and slices of bytes. It said nothing about arrays of bytes. But in fact, if I put an array of bytes in it, it prints out fine too!

package main

import (
  &quot;fmt&quot;
)

func main() {
  var b [6]byte
  for i := 0; i &lt; 6; i++ {
    b[i] = &#39;a&#39;
  }
  fmt.Printf(&quot;%s\n&quot;, b) // &quot;aaaaaa&quot;
}

Can anyone please tell me why? AFAIK, bytes array and slices cannot implicitly convert to each other.

Thanks for reading my question!

答案1

得分: 12

你是正确的,你不能隐式地转换切片和数组。

切片是一个小的数据结构,包含三个元素:指向某个内存的指针、内存的长度和内存的容量。

然而,数组只是一块内存。

Go 在函数中将所有内容都按值传递,这意味着当你用数组调用 Printf 时,整个数组的内存都会传递给函数。当你用切片调用它时,整个切片结构都会传递给 Printf。然而,切片结构包含指向底层内存的指针,所以这很像是传递一个指向数组的指针。

Printf 使用了很多内省来打印其值。Printf 的所有参数都被转换为 interface{} 类型,这意味着它们被封装在一个带有类型的小结构中。然后,Printf 检查这些接口值,检查类型并确定如何打印这些值。对于大多数 % 类型,Printf 可以接受多种类型,并尝试以用户友好的方式打印它们。

例如,%x 可以接受一个以十六进制打印的 int,或者一个切片,或者一个数组,正如你已经发现的那样。

所以总结一下:

  • 数组是连续的内存
  • 切片是一个包含指向连续内存的指针的结构
  • 接口值是一个小结构,包含指向类型和值的指针
  • Printf 接受 interface{}
  • 它内省 interface{} 值以打印很多不同的东西

希望这个解释对你有帮助!

英文:

You are correct that you can't implicitly convert slices and arrays.

A slice is a small data structure with 3 elements which are a pointer to some memory, the length of the memory, and the capacity of the memory.

However an array is just a block of memory.

Go passes everything by value in functions meaning that when you call Printf with the array, the whole of the memory of the array is passed to the function. When you call it with a slice, the whole of the slice structure is passed to Printf. However the slice structure contains a pointer to the underlying memory so this is very like passing a pointer to an array.

Printf uses lots of introspection to print its values. All the arguments to Printf are converted to interface{} types which means they are boxed up with a type in a small structure. Printf then examines these interface values, inspects the type and works out how to print the values. For most % types that Printf undestands it can take quite a few types and it attempts to print them in a user friendly way.

For example %x can take an int which is printed in hex, or a slice, or an array as you've discovered.

So in summary

  • array is contiguous memory
  • slice is a structure containing a pointer to contiguous memory
  • an interface value is a small structure containing a pointer to a type and the value
  • Printf takes interface{} values
  • It introspects the interface{} values to print lots of different things

I hope that explanation is helpful!

huangapple
  • 本文由 发表于 2014年5月2日 15:03:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/23422599.html
匿名

发表评论

匿名网友

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

确定