当golang是本机类型时,为什么golang禁止分配给相同的基础类型?

Consider this code:

package main
import "fmt"

type specialString string

func printString(s string) {
    fmt.Println(s)
}

// unlike, say, C++, this is not legal GO, because it redeclares printString
//func printString(s specialString) {    
//  fmt.Println("Special: " + s)
//}

func main() {
    ss := specialString("cheese")
    // ... so then why shouldn't this be allowed?
    printString(ss)
}

My question is: why is the language defined so that the call to printString(ss) in main() is not allowed? (I'm not looking for answers that point to the Golang rules on assignment; I have already read them, and I see that both specialString and string have the same 'underlying type' and both types are 'named' -- if you consider the generic type 'string' to be named, which Golang apparently does -- and so they are not assignable under the rules.)

But why are the rules like that? What problem is solved by treating the built-in types as 'named' types, and preventing you from passing named types to all the standard library functions that accepting the same underlying built-in type? Does anybody know what the language designers had in mind here?

From my point of view, it seems to create a lot of pointless type conversion in the code, and discourages the use of strong typing where it actually would make sense..

I believe the initial authors' logic here is that named type is named for a reason - it represents something different, not just underlying type.

I guess I've read it somewhere in golang-nuts, but can't remember exact discussion.

Consider the following example:

type Email string

You named it Email, because you need to represent e-mail entity, and 'string' is just simplified representation of it, sufficient for the very start. But later, you may want to change Email to something more complex, like:

type Email struct {
    Address string
    Name    string
    Surname string
}

And that will break all your code that work with Email implicitly assuming it's a string.

This is because Go does not have class inheritance. It uses struct composition instead. Named types do not inherit properties from their underlying type (that's why it's not called "base type").

So when you declare a named type specialString with an underlying type of a predefined type string, your new type is a completely different type from the underlying one. This is because Go assumes you will want to assign different behaviors to your new type, and will not check its underlying type until run-time. This is why Go is both a static and dynamic language.

When you print

fmt.Println(reflect.TypeOf(ss))        // specialString

You get specialString, not string. If you take a look at Println() the definition is as follows:

func Println(a ...interface{}) (n int, err error) {
        return Fprintln(os.Stdout, a...)
}

This means you can print any predeclared types (int, float64, string) because all of them implements at least zero methods, which makes them already conform to the empty interface and pass as "printable", but not your named type specialString which remains unknown to Go during compile time. We can check by printing the type of our interface{} against specialString.

type specialString string 
type anything interface{}

s := string("cheese")
ss := specialString("special cheese")
at := anything("any cheese")

fmt.Println(reflect.TypeOf(ss))     // specialString
fmt.Println(reflect.TypeOf(s))      // string
fmt.Println(reflect.TypeOf(at))     // Wow, this is also string!

You can see that specialString keeps being naughty to its identity. Now, see how it does when passed into a function at run-time

func printAnything(i interface{}) {
        fmt.Println(i)
}

fmt.Println(ss.(interface{}))       // Compile error! ss isn't interface{} but
printAnything(ss)                   // prints "special cheese" alright

ss has become passable as interface{} to the function. By that time Go has already made ss an interface{}.

If you really want to understand deep down the hood this article on interfaces is really priceless.