func (s *service) registerMethods() {
s.method = make(map[string]*methodType)
for i := 0; i < s.typ.NumMethod(); i++ {
method := s.typ.Method(i)
mType := method.Type
if mType.NumIn() != 3 || mType.NumOut() != 1 {
continue
}
if mType.Out(0) != reflect.TypeOf((*error)(nil)).Elem() {
continue
}
argType, replyType := mType.In(1), mType.In(2)
if !isExportedOrBuiltinType(argType) || !isExportedOrBuiltinType(replyType) {
continue
}
s.method[method.Name] = &methodType{
method: method,
ArgType: argType,
ReplyType: replyType,
}
log.Printf("rpc server: register %s.%s\n", s.name, method.Name)
}
}
what does reflect.TypeOf((*error)(nil)).Elem()
mean in this code? I know if mType.Out(0) != reflect.TypeOf((*error)(nil)).Elem()
is trying to determine if the method's return type is error not not. But for me, reflect.TypeOf((error)(nil))
intuitively will do the same, but unfortunately not. When I try to compile this code, it says type error is not an expression, what does it mean in this context? Does not reflect.Typeof()
accepts a argument of certain type? I found that (*error)(nil) is equivalent to *error = nil. I am confused with this expression.
TL;DR;
reflect.TypeOf((*error)(nil)).Elem()
is an expression used to obtain thereflect.Type
type descriptor of the interface typeerror
. Usingreflect.TypeOf(error(nil))
cannot be used for the same purpose (read the why below).reflect.TypeOf((*error)(nil)).Elem()
achieves its goal by using a typednil
pointer value of type*error
, passing it toreflect.TypeOf()
to get thereflect.Type
descriptor of the type*error
, and usesType.Elem()
to get the type descriptor of the element (base) type of*error
, which iserror
.reflect.TypeOf()
expects aninterface{}
value:Basically whatever value you pass to
reflect.TypeOf()
, if it's not already an interface value, it will be wrapped in aninterface{}
implicitly. If the passed value is already an interface value, then the concrete value stored in it will be passed asinterface{}
.So if you try to pass an
error
value to it, sinceerror
is an interface type, the concrete value stored in it will be "repacked" into aninterface{}
value. The interface typeerror
will not be retained / transferred!If you pass a
nil
value of typeerror
, e.g.error(nil)
, since the interface value itself isnil
, it contains no concrete value and type, anil
interface{}
value will be passed, that will result innil
reflect.Type
returned. Quoting fromreflect.TypeOf()
:If you pass a value of type
*error
(which may be anil
pointer), it's not an interface value, it's a pointer value (a pointer to interface). So it will be wrapped in aninterface{}
value, and the concrete value stored in it will be of type*error
. UsingType.Elem()
you can access the pointed type, that iserror
.This is one of the rare cases when using a pointer to interface makes sense, and in fact inevitable.
See related questions:
Get the reflect.Kind of a type which is based on a primitive type
What is the difference between reflect.ValueOf() and Value.Elem() in go?
Hiding nil values, understanding why golang fails here