<p>I'm following a book which shows the following example.</p>
<pre><code>package main
import (
"fmt"
)
const (
KB = 1024
MB = 1048576 //KB * 1024
GB = 1073741824 //MB * 1024
TB = 1099511627776 //GB * 1024
PB = 1125899906842624 //TB * 1024
)
type ByteSize float64
func (b ByteSize) String() string {
switch {
case b >= PB:
return "Very Big"
case b >= TB:
return fmt.Sprintf("%.2fTB", b/TB)
case b >= GB:
return fmt.Sprintf("%.2fGB", b/GB)
case b >= MB:
return fmt.Sprintf("%.2fMB", b/MB)
case b >= KB:
return fmt.Sprintf("%.2fKB", b/KB)
}
return fmt.Sprintf("%dB", b)
}
func main() {
fmt.Println(ByteSize(2048))
fmt.Println(ByteSize(3292528.64))
}
</code></pre>
<p>When I run this program it gives me the following output (in human readable data size units).</p>
<pre><code>2.00KB
3.14MB
</code></pre>
<p>But when I change the name of the function called String() to anything else, or if I lower-case the S in String, it gives me the following output.</p>
<pre><code>2048
3.29252864e+06
</code></pre>
<p>What is the reason behind that? Is there some String() function attached to some interface and our ByteSize type satisfies that interface? I mean what the hell?</p>
<hr/>**评论:**<br/><br/>rauyran: <pre><p>Yes. Take a look at <a href="https://godoc.org/fmt#Stringer" rel="nofollow">https://godoc.org/fmt#Stringer</a></p></pre>nevyn: <pre><p>Probably also worth linking to: <a href="https://gobyexample.com/interfaces" rel="nofollow">https://gobyexample.com/interfaces</a></p></pre>avidal: <pre><p>That's exactly correct. There's an interface <a href="https://godoc.org/fmt" rel="nofollow"><code>fmt.Stringer</code></a> which, if implemented on your type, is used to get the string representation when calling <code>fmt.Print</code> and family.</p></pre>deusmetallum: <pre><p>It has to be called String() because fmt.Println is simply checking to see if that function exists. It can't check for all possible itterations!</p>
<p>Further more, anything beginning with a capitol letter is an "exported" function, meaning it can be run from any other package when imported. If you make the S lowercase, then the function can't be run in another module.</p></pre>deusmetallum: <pre><p>Also, if you change the name to string() or whatever(), you'd have to change your fmt.Println lines to look like this:</p>
<pre><code>fmt.Println(ByteSize(2048).string())
</code></pre></pre>magpiecub: <pre><pre><code>const (
KB = 1024
MB = 1048576 //KB * 1024
GB = 1073741824 //MB * 1024
TB = 1099511627776 //GB * 1024
PB = 1125899906842624 //TB * 1024
)
</code></pre>
<p>If <code>MB</code> is <code>KB * 1024</code> as the comment suggests, why don't they just write <code>MB = KB * 1024</code>?</p></pre>Indu_Pillai: <pre><p>I changed that myself. Just cultivating the habit of reducing unwanted computations. :)</p></pre>magpiecub: <pre><p>Computers are fast and cheap. Humans are slow and expensive. You shouldn't be sacrificing readability to prevent 4 multiplication operations.</p>
<p>The operations don't even happen at run time - they happen at compile time:</p>
<pre><code>% cat > main.go
package main
import "fmt"
const x = 2
func main() {
fmt.Println(x)
}
% go build -o x2 main.go
% cat > main.go
package main
import "fmt"
const x = 1 + 1
func main() {
fmt.Println(x)
}
% go build -o x11 main.go
% sha1sum x2 x11
515ccebaedfdedd5f3adba0d600b1d02873670b6 x2
515ccebaedfdedd5f3adba0d600b1d02873670b6 x11
</code></pre></pre>Indu_Pillai: <pre><p>so it means the value of constants is calculated at the compile time?</p></pre>zevdg: <pre><p>In recent versions of Go, yes. it's one of the many optimizations enabled by the recent SSA compiler work and is specifically called out in <a href="https://www.youtube.com/watch?v=uTMvKVma5ms" rel="nofollow">this video</a> from Gophercon 2017.</p>
<p>That said, even if it weren't, you're talking about obfuscating your source code to gain fractions of nanoseconds at runtime. That's NEVER the right trade off unless you've profiled your code and found this particular path to be worth optimizing. Donald Knuth (who probably knows more about optimizing code than either of us ever will) famously said</p>
<blockquote>
<p>The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming.</p>
</blockquote>
<p>And he said it again in this way</p>
<blockquote>
<p>Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.</p>
</blockquote>
<p>Please don't give into this evil. Always start by writing readable code and then if/when you need better performance, profile your code and only optimize the bottlenecks. Trust me, the people who you ask for help from (like us) will really appreciate it and be even be more likely to help if they can understand your code at a glance.</p></pre>rpk788: <pre><p>All of the other answers about implementing the Stringer interface are great. It is also worth mentioning that capitalization plays a big role in Go as well. so swapping the method name from String() to string() is more significant than you might think. See here: </p>
<p><a href="https://tour.golang.org/basics/3" rel="nofollow">https://tour.golang.org/basics/3</a></p></pre>
Why does the following Go program need the function's name to be String() and not anything else?
agolangf · · 439 次点击这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传