I often see codes which define custom type with underlying type.
However there seem to be some confused behaviors.
-
string
can be assign asMethod
without cast -
string
can be used for function argument asMethod
without cast -
string
cannot become receiver forMethod
functions -
Method
cannot be assign asstring
without cast -
Method
can be used for function argument asstring
without cast
This can be regarded as consistent, like the relation between super class and subclass in OOP(but string
is subclass from implicit cast point of view interesting.) but in the example below you may
incorrectly use B
and C
as Method
unless defining receiver methods.
Changing behaviors will lose backward compatibility so there is no need to do anything for Go codes, in my opinion.
But this could cause bugs in some case, for example you write codes which depends on reflect.TypeOf
or type cast.
Do you have any ideas to reduce these risks and misunderstandings?
https://play.golang.org/p/G7EosLYLGZj
type Method string
const (
A Method = "A" // A is Method
B = "B" // B is string
C = "C" // C is string
)
func (m Method) String() string {
return string(m)
}
func ToMethod(m string) Method {
switch m {
case "A":
return A
case "B":
return B
case "C":
return C
default:
return A
}
}
func ToString(m Method) string {
return string(m)
}
func AsString(m string) string {
return m
}
type MethodConfig struct {
method Method
methodStr string
}
func main() {
fmt.Println(A.String())
//fmt.Println(B.String())
//fmt.Println(C.String())
fmt.Println(reflect.TypeOf(A))
fmt.Println(reflect.TypeOf(B))
fmt.Println(reflect.TypeOf(C))
a := ToMethod("A")
b := ToMethod("B")
c := ToMethod("C")
fmt.Println(a.String())
fmt.Println(b.String())
fmt.Println(c.String())
fmt.Println(reflect.TypeOf(a))
fmt.Println(reflect.TypeOf(b))
fmt.Println(reflect.TypeOf(c))
ToString(A)
ToString(B)
ToString(C)
//AsString(A)
AsString(B)
AsString(C)
cfgA := MethodConfig{method: A}
cfgB := MethodConfig{method: B, methodStr: B}
cfgC := MethodConfig{method: C, methodStr: C}
fmt.Println(cfgA.method.String())
fmt.Println(cfgB.method.String())
fmt.Println(cfgC.method.String())
fmt.Println(reflect.TypeOf(cfgA.method))
fmt.Println(reflect.TypeOf(cfgB.method))
fmt.Println(reflect.TypeOf(cfgC.method))
}
Of course, the example below works consistently👍
(The misunderstanding may be caused by int iota
sample😅)
type TimeZone int
const (
EST TimeZone = -(5 + iota)
CST
MST
PST
)
func (tz TimeZone) String() string {
return fmt.Sprintf("GMT%+dh", tz)
}