go 指针类似格式参数的行为未记录在案,

zz2j4svz  于 4个月前  发布在  Go
关注(0)|答案(8)|浏览(151)

函数和通道有一个共同点 - 它们都在底层是指针。这意味着可以使用 %p 来打印它们,就像实际的指针一样。
文档中提到了 %b, %d, %o, %x and %X verbs also work with pointers,因此也可以用于函数和通道。
但是在格式化时,没有文档说明通道和函数会被当作指针处理。最接近的是这段内容:

The default format for %v is:
[...]
chan:                    %p

我认为我们应该扩展文档以澄清一些事情:

  • 函数和通道的打印方式与指针完全相同
  • 函数 %v 的默认格式也是 %p
  • 只有使用 %p 时,Map才会像指针一样打印

最后一点尤其棘手。例如,fmt.Printf("%p", map[bool]bool{true: false} 将正确地打印地址,但 %b%d 也会失败,因为 fmt 递归到键和值元素,而这些元素不是数字。
我在修复 vet 中的一些错误时遇到了这个问题,我对 fmt 如何如此轻率地记录所有这些行为感到惊讶。其中一些行为也让我感到惊讶。我会很快发送一个文档 CL 草稿。
/cc @robpike@alandonovan@martisch

vom3gejh

vom3gejh1#

这甚至更令人困惑——这里有一些兽医printf测试用例:

// Can't print a function.
Printf("%d", someFunction) // want "Printf format %d arg someFunction is a func value, not called"
Printf("%v", someFunction) // want "Printf format %v arg someFunction is a func value, not called"
Println(someFunction)      // want "Println arg someFunction is a func value, not called"
Printf("%p", someFunction) // ok: maybe someone wants to see the pointer
Printf("%T", someFunction) // ok: maybe someone wants to see the type

因此,fmt允许通过%d%v打印一个函数,但vet不行。其中一个是错误的。我希望它是fmt,在这种情况下,我们需要澄清文档并修复这个bug。

5rgfhyps

5rgfhyps2#

我会等待一些确认信息,然后再发送CL,因为我不能100%确定vet是正确的,而fmt关于fmt.Printf("%d", someFunc)是错误的。但是我相当肯定,因为vet已经作为go test的一部分运行了一段时间。所以如果有人依赖于这种行为,他们现在应该已经提出问题了。

daolsyd0

daolsyd03#

你为什么相信vet胜过fmt?因为vet模拟了fmt,但模拟是错误的。

cidc1ykv

cidc1ykv4#

I'd hope that both fmt and vet implementations follow the fmt docs, which are ambiguous when it comes to formatting functions.
Generally I'd trust the fmt implementation over vet's, but vet has had this check since 2015 ( 43a7a9c ) and we've enforced it via go test since 1.10, almost a year ago. So my point is that we could probably change fmt instead of changing vet, since go test should already have been failing on any programs disagreeing with vet.
That aside - @robpike, could you clarify if fmt's treatment of pointer-like types is as initially designed? If it is correct, then I'll just clarify the fmt docs and update vet to comply.

6l7fqoea

6l7fqoea5#

嗯,这很棘手。在这种情况下,我相信两者都是正确的。
Fmt允许打印一个函数,因为你可能需要它进行调试。
Vet报告说,在不调用函数的情况下打印函数是一个很可能的错误。
我不会改变任何一个。当vet不在构建路径中时,这不是一个问题。现在还不清楚这是否是一个问题,因为在生产代码中没有可能打印函数的故事,但在调试时打印几乎任何东西都是合理的。

7hiiyaii

7hiiyaii6#

嗯,这很棘手。在这种情况下,我相信两者都是正确的。
这个问题是关于澄清fmt文档以使其清晰和精确的,在这种情况下,要么fmt的实现,要么vet的都会出错 :)
Fmt允许打印一个函数,因为你可能需要它进行调试。
Vet报告说在不调用的情况下打印一个函数是一个很可能的错误。
我认为在这里有一个重要的区分。像%x这样的动词似乎对于调试函数指针是合理的。另一方面,对于像%d%v这样的动词,我同意vet的观点,它很可能是一个bug。
%x 是否足以调试函数指针?如果是,我们可以更改fmt文档以与vet的警告相一致。如果我们这样做了,那么为了保持一致性,我可能还会使通道只能使用%p进行打印,其中%v仍然默认为%p
另一方面,如果我们认为改变fmt的行为是不可接受的,我认为我们将面临一个艰难的决定。留下fmt文档的模糊性是糟糕的,失去有用的vet警告也是糟糕的。

bnlyeluc

bnlyeluc7#

建议文档应该写什么内容。我更不希望改变fmt的行为;每次我们这样做,它接触到的代码比我们预期的要多得多,而且/或者会被回滚。

56lgkhnf

56lgkhnf8#

这是一个很好的观点;我们最近已经被这个问题困扰了:)也许所有的这些小fmt怪癖都可以在将来的fmt包的v2版本中得到修复。

相关问题