【问题标题】:TypeOf without an instance and passing result to a funcTypeOf 没有实例并将结果传递给 func
【发布时间】:2018-08-03 00:17:09
【问题描述】:

是否有可能在没有实例的情况下获得“类型”?我见过一些使用reflect.TypeOf() 的示例,但它们都处理一个实例。

下面是我正在尝试做的一个 sn-p:

import (
    "net/http"
)

type ParamReader struct {
    // The request from which to extract parameters
    context *http.Request
}

// Initialize the ParamReader with a specific http request. This serves
// as the 'context' of our param reader. All subsequent calls will validate
// the params that are present on this assigned http.Request
func (p *ParamReader) Context(r *http.Request) {
    p.context = r
}

// Validate that a given param 's' is both present and a valid
// value of type 't'. A value is demeed valid if a conversion from 
// its string representation to 't' is possible
func(p *ParamReader) Require(s string, t Type) {
    // if context not have 's'
    //      addError('s' is not present)
    //      return


    if( t == typeof(uint64)) {
        // If not s -> uint64
        //      addError('s' is not a valid uint64)
    } else if (t == typeof(uint32)) {
        // ....
    } / ....
}

我的用法是

func (h *Handler) OnRequest(r *http.Request) {
  h.ParamReader.Context(r)
  h.ParamReader.Require("age", uint16)
  h.ParamReader.Require("name", string)
  h.ParamReader.Require("coolfactor", uint64)
  h.ParamReader.Optional("email", string, "unspecified")
  h.ParamReader.Optional("money", uint64, "0")

  if h.ParamReader.HasErrors() {
    // Iterate or do something about the errors
  } else {
    coolness := h.ParamReader.ReadUint64("coolfactor")
    email := h.ParamReader.ReadString("email")
    money := h.ParamReader.ReadUint64(0)
  }
}

注意,写完后,我意识到我可以提供"RequireUint64""RequireUint32" 等。也许这就是 Go 方式?

【问题讨论】:

  • @tkausl,这个例子几乎就像我想要完成的那样。唯一的区别是他们传入"hello" 的地方,我想传入typeof(string) 之类的东西。我的用例是我实际上没有该示例所示的实例。

标签: go reflection types


【解决方案1】:

是的,这是可能的。诀窍是从指向类型的指针开始(其值可以是 typed nil,这完全可以),然后使用 Type.Elem() 获取指向的 reflect.Type 描述符类型(基础类型)。

看一些例子:

t := reflect.TypeOf((*int)(nil)).Elem()
fmt.Println(t)

t = reflect.TypeOf((*http.Request)(nil)).Elem()
fmt.Println(t)

t = reflect.TypeOf((*os.File)(nil)).Elem()
fmt.Println(t)

输出(在Go Playground上试试):

int
http.Request
os.File

查看相关问题:

Golang reflect: Get Type representation from name?

How to get the string representation of a type?

如果你想在switches中传递类型并使用它们,你可以像这样创建并存储它们一次在全局变量中,并引用全局变量:

var (
    intType         = reflect.TypeOf((*int)(nil))
    httpRequestType = reflect.TypeOf((*http.Request)(nil))
    osFileType      = reflect.TypeOf((*os.File)(nil))
    int64Type       = reflect.TypeOf((*uint64)(nil))
)

func printType(t reflect.Type) {
    switch t {
    case intType:
        fmt.Println("Type: int")
    case httpRequestType:
        fmt.Println("Type: http.request")
    case osFileType:
        fmt.Println("Type: os.file")
    case int64Type:
        fmt.Println("Type: uint64")
    default:
        fmt.Println("Type: Other")
    }
}

func main() {
    printType(intType)
    printType(httpRequestType)
    printType(osFileType)
    printType(int64Type)
}

上面的输出(在Go Playground上试试):

Type: int
Type: http.request
Type: os.file
Type: uint64

但老实说,如果您以这种方式使用它并且不使用reflect.Type 的方法,那么创建常量会更容易和更有效。它可能看起来像这样:

type TypeDesc int

const (
    typeInt TypeDesc = iota
    typeHttpRequest
    typeOsFile
    typeInt64
)

func printType(t TypeDesc) {
    switch t {
    case typeInt:
        fmt.Println("Type: int")
    case typeHttpRequest:
        fmt.Println("Type: http.request")
    case typeOsFile:
        fmt.Println("Type: os.file")
    case typeInt64:
        fmt.Println("Type: uint64")
    default:
        fmt.Println("Type: Other")
    }
}

func main() {
    printType(typeInt)
    printType(typeHttpRequest)
    printType(typeOsFile)
    printType(typeInt64)
}

输出是一样的。在Go Playground 上试试吧。

【讨论】:

  • 这似乎是要走的路,我可以用它来解决问题。虽然我不完全确定如何在Elem 上进行切换或比较,但我修改了您的示例,使其更接近于我所拍摄的内容:play.golang.org/p/aLyzzjjHgHD。我选择了这条路线并将reflect.TypeOf 包装在一个“更”可读且简洁的辅助函数和结构中,以明确哪些“ParamTypes”是有效的。
  • @bgura 添加了使用示例。此外,如果您要这样使用它,则常量更合适。请参阅编辑后的答案。
  • 好点。这个答案现在确实涵盖了 Go 可以解决问题的多种方式。
【解决方案2】:

我相当肯定这在 Go 中是不可能的。虽然它远非理想,但您可以使用 Type.Name()string 作为函数 arg 来进行任何必要的比较。

package main

import (
    "fmt"
    "reflect"
)

func main() {
    printIt("int")
}

func printIt(x string) {
    i := 10
    if (reflect.TypeOf(i).Name() == x) {
        fmt.Println(x)
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-06
    • 1970-01-01
    • 1970-01-01
    • 2021-05-09
    • 2021-12-10
    • 2019-10-23
    • 2011-05-10
    相关资源
    最近更新 更多