为什么以下Go程序需要函数的名称为String()而不是其他名称?

为什么以下Go程序需要函数的名称为String()而不是其他名称?

问题描述:

I'm following a book which shows the following example.

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))
}

When I run this program it gives me the following output (in human readable data size units).

2.00KB
3.14MB

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.

2048
3.29252864e+06

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?

When you define a method named String with no parameters returning a string, you implement the Stringer interface, which is documented here: https://golang.org/pkg/fmt/#Stringer.

Your last sentence is exactly right. In Go, you can satisfy interfaces you didn't even know existed. And you can write new interfaces for other people's functions. Their code does not have to write "implement" or derive or anything. It is entirely based on the function name and having a matching argument and return value list.

The example is very similar to an example in "Effective Go" by the Go Authors, and the meaning of the String() method described there.

The ability to attach a method such as String to any user-defined type makes it possible for arbitrary values to format themselves automatically for printing. Although you'll see it most often applied to structs, this technique is also useful for scalar types such as floating-point types like ByteSize.

See: https://golang.org/doc/effective_go.html#constants