英文:
How to create a slice of a type given as parameter in Golang? or how to give a []interface{} to Appengine datastore getAll
问题
我正在尝试创建一个适用于多种实体类型的处理程序生成器。
以下代码适用于特定类型的items切片(例如:var items []Person
),但我在泛化它时遇到了问题:具体来说是"ERROR: Can't get items: datastore: invalid entity type"。
有没有办法声明items的类型,使其对GetAll有效?
func ScaffoldList(entity interface{}, collection string, templ *template.Template) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
c := appengine.NewContext(r)
T := reflect.TypeOf(entity)
q := datastore.NewQuery(T.String())
items := reflect.MakeSlice(reflect.SliceOf(T), 0, 10)
_, err := q.GetAll(c, &items)
if err != nil{
c.Errorf("Can't get items: %v", err)
http.Error(w, "Can't get items", http.StatusInternalServerError)
return
}
context.Set(r, collection, items)
ion.RenderTemplate(templ).ServeHTTP(w, r)
})
}
英文:
I'm trying to create a generator of handlers that works for several kinds of entities.
The following code works if the items slice is of a specific type (eg: var items []Person
), but I'm having problems generalizing it: specifically "ERROR: Can't get items: datastore: invalid entity type
".
Any idea of how to declare items so that it have a type valid for GetAll?
func ScaffoldList(entity interface{}, collection string, templ *template.Template) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
c := appengine.NewContext(r)
T := reflect.TypeOf(entity)
q := datastore.NewQuery(T.String())
items := reflect.MakeSlice(reflect.SliceOf(T), 0, 10)
_, err := q.GetAll(c, &items)
if err != nil{
c.Errorf("Can't get items: %v", err)
http.Error(w, "Can't get items", http.StatusInternalServerError)
return
}
context.Set(r, collection, items)
ion.RenderTemplate(templ).ServeHTTP(w, r)
})
}
答案1
得分: 2
这是如何获取类型为*[]Person的参数的方法:
items := reflect.New(reflect.SliceOf(T))
_, err := q.GetAll(c, items.Interface())
GetAll将为切片分配后备数组。不需要使用make
预先分配后备数组。
假设context.Set的参数是包含切片的值,那么你需要解引用指针:
context.Set(r, collection, items.Elem())
如果上下文不适用于反射值,那么你可能想要:
context.Set(r, collection, items.Elem().Interface())
英文:
Here's how you get an argument of type *[]Person:
items := reflect.New(reflect.SliceOf(T))
_, err := q.GetAll(c, items.Interface())
GetAll will allocate the backing array for the slice. There's no need to preallocate the backing array with make
.
Assuming that the argument to context.Set is a value containing a slice, then you need to dereference the pointer:
context.Set(r, collection, items.Elem())
If the context does not work with reflect values, then you probably want:
context.Set(r, collection, items.Elem().Interface())
答案2
得分: 0
至少有两个基于代码生成器的工具可以创建类型安全的参数化代码。我知道的两个工具是:
我目前正在使用Gen。虽然它不像内置的语言特性那样无缝,但它是生成通用集合类型等的好方法。Gen模板被称为typewriters(打字机)。使用提供的typewriters非常容易。创建自己的typewriters需要更多的工作。
Gen使用Go模板包来工作。因此,typewriters只是作为字符串编写;直到生成输出代码时,编译器才会检查它们(这是一个小缺点)。
相反,Genny试图允许您编写包含通用标记类型的可编译代码,然后用具体类型替换通用标记。这是一种更简单的方法,但对我来说并不总是有效。
英文:
There are at least two code-generator based tools for creating type-safe parameterised code. The two I know of are
I am currently using Gen. It's not as seamless as a built-in language feature might be, but it's a good way to produce generic collection types etc. Gen templates are called typewriters. Using the provided typewriters is really quite easy. Creating your own is a bit more work.
Gen works using the Go template package. So the typewriters are written merely as strings; the compiler doesn't check them until output code is created (a minor drawback).
Conversely, Genny tries to allow you to write compilable code containing generic marker types, and then it substitutes the generic markers with specific types. This is a simpler approach but didn't always work for me.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论