what does reflect.TypeOf((*error)(nil)).Elem()` mean?

huangapple go评论87阅读模式
英文:

what does reflect.TypeOf((*error)(nil)).Elem()` mean?

问题

reflect.TypeOf((*error)(nil)).Elem() 是用于获取 error 类型的反射类型对象的方法。在这段代码中,reflect.TypeOf((*error)(nil)) 返回的是 *error 类型的反射类型对象,而 .Elem() 方法则返回指针类型的基础类型,也就是 error 类型的反射类型对象。

在这段代码中,if mType.Out(0) != reflect.TypeOf((*error)(nil)).Elem() 的作用是判断方法的返回类型是否为 error 类型。通过使用 reflect.TypeOf((*error)(nil)).Elem(),我们可以获取到 error 类型的反射类型对象,然后与方法的返回类型进行比较,以确定返回类型是否为 error

关于 (*error)(nil) 的使用,它表示一个空的 error 指针。在这里,我们需要使用指针类型来获取 error 的反射类型对象,因此使用 (*error)(nil) 来表示一个空的 error 指针。

你提到在编译代码时遇到了 type error is not an expression 的错误。这是因为 error 是一个接口类型,而不是一个具体的类型,所以不能直接使用 reflect.TypeOf(error) 来获取其反射类型对象。通过使用 (*error)(nil),我们可以创建一个空的 error 指针,然后使用 reflect.TypeOf() 来获取其反射类型对象。

希望这能解答你的疑惑!如果还有其他问题,请随时提问。

英文:
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.

答案1

得分: 7

reflect.TypeOf((*error)(nil)).Elem() 是一个表达式,用于获取接口类型 errorreflect.Type 类型描述符。使用 reflect.TypeOf(error(nil)) 不能用于相同的目的(请阅读下面的原因)。


reflect.TypeOf((*error)(nil)).Elem() 通过使用类型为 *error 的有类型 nil 指针值,将其传递给 reflect.TypeOf() 来实现其目标,以获取类型为 *errorreflect.Type 描述符,并使用 Type.Elem() 获取 *error 的元素(基本)类型的类型描述符,即 error

reflect.TypeOf() 期望一个 interface{} 值:

func TypeOf(i interface{}) Type

基本上,无论您传递给 reflect.TypeOf() 的值是什么,如果它还不是一个接口值,它将被隐式地包装在一个 interface{} 中。如果传递的值已经是一个接口值,那么存储在其中的具体值将作为 interface{} 传递。

因此,如果您尝试将一个 error 值传递给它,由于 error 是一个接口类型,存储在其中的具体值将被“重新打包”为一个 interface{} 值。接口类型 error 将不会被保留/传递!

如果您传递一个类型为 errornil 值,例如 error(nil),由于接口值本身是 nil,它不包含具体值和类型,将传递一个 nilinterface{} 值,这将导致返回 nilreflect.Type。引用自 reflect.TypeOf()

> TypeOf 返回表示 i 的动态类型的反射类型。如果 i 是一个 nil 接口值,则 TypeOf 返回 nil。

如果您传递一个类型为 *error 的值(可能是一个 nil 指针),它不是一个接口值,而是一个指针值(指向接口的指针)。因此,它将被包装在一个 interface{} 值中,并且存储在其中的具体值将是 *error 类型。使用 Type.Elem() 您可以访问指向的类型,即 error

这是使用指向接口的指针的少数几种情况之一,事实上是不可避免的。

参考相关问题:

https://stackoverflow.com/questions/63938572/get-the-reflect-kind-of-a-type-which-is-based-on-a-primitive-type/63938859#63938859

https://stackoverflow.com/questions/57388657/what-is-the-difference-between-reflect-valueof-and-value-elem-in-go/57388715#57388715

https://stackoverflow.com/questions/29138591/hiding-nil-values-understanding-why-golang-fails-here/29138676#29138676

英文:

TL;DR; reflect.TypeOf((*error)(nil)).Elem() is an expression used to obtain the reflect.Type type descriptor of the interface type error. Using reflect.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 typed nil pointer value of type *error, passing it to reflect.TypeOf() to get the reflect.Type descriptor of the type *error, and uses Type.Elem() to get the type descriptor of the element (base) type of *error, which is error.

reflect.TypeOf() expects an interface{} value:

func TypeOf(i interface{}) Type

Basically whatever value you pass to reflect.TypeOf(), if it's not already an interface value, it will be wrapped in an interface{} implicitly. If the passed value is already an interface value, then the concrete value stored in it will be passed as interface{}.

So if you try to pass an error value to it, since error is an interface type, the concrete value stored in it will be "repacked" into an interface{} value. The interface type error will not be retained / transferred!

If you pass a nil value of type error, e.g. error(nil), since the interface value itself is nil, it contains no concrete value and type, a nil interface{} value will be passed, that will result in nil reflect.Type returned. Quoting from reflect.TypeOf():

> TypeOf returns the reflection Type that represents the dynamic type of i. If i is a nil interface value, TypeOf returns nil.

If you pass a value of type *error (which may be a nil pointer), it's not an interface value, it's a pointer value (a pointer to interface). So it will be wrapped in an interface{} value, and the concrete value stored in it will be of type *error. Using Type.Elem() you can access the pointed type, that is error.

This is one of the rare cases when using a pointer to interface makes sense, and in fact inevitable.

See related questions:

https://stackoverflow.com/questions/63938572/get-the-reflect-kind-of-a-type-which-is-based-on-a-primitive-type/63938859#63938859

https://stackoverflow.com/questions/57388657/what-is-the-difference-between-reflect-valueof-and-value-elem-in-go/57388715#57388715

https://stackoverflow.com/questions/29138591/hiding-nil-values-understanding-why-golang-fails-here/29138676#29138676

huangapple
  • 本文由 发表于 2021年8月21日 02:24:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/68866632.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定