英文:
Access Custom Type's Original Functions
问题
如何在Go中访问自定义类型的原始函数?
我不认为这与gqlgen
有关,但我的用例与他们的框架密切相关。我正在尝试在gqlgen
中为日期构建自定义标量,按照他们在这里的设置:https://gqlgen.com/reference/scalars/
我在MarshalGQL
函数中遇到了困难。以下是我目前的代码:
package scalars
import (
"fmt"
"io"
"time"
)
type Date time.Time
// UnmarshalGQL implements the graphql.Unmarshaler interface
func (date *Date) UnmarshalGQL(value interface{}) error {
dateAsString, ok := value.(string)
if !ok {
return fmt.Errorf("date must be a string")
}
parsedTime, err := time.Parse(time.RFC3339, dateAsString)
if err != nil {
return fmt.Errorf("failed to convert given date value (%s) to Time struct", dateAsString)
}
*date = Date(parsedTime)
return nil
}
// MarshalGQL implements the graphql.Marshaler interface
func (date Date) MarshalGQL(w io.Writer) {
// 这一行导致编译错误
w.Write(date.Format(time.RFC3339))
}
我的问题在于这一行:w.Write(date.Format(time.RFC3339))
它给我返回了这个编译错误:
date.Format未定义(类型Date没有字段或方法Format)编译器(MissingFieldOrMethod)
我理解它为什么这样说。根据编译器的了解,Date
类型只有两个函数,即UnmarshalGQL
和MarshalGQL
,它们都在这个文件中声明。然而,我想要访问time.Time
类型的函数,以便格式化返回的日期。我该如何做到这一点?
英文:
How do I access the original functions of a customized type in Go?
I do not believe this is not specific to gqlgen
, but my use-case heavily involves their framework. I'm trying to build a custom scalar for dates in gqlgen
following their setup here: https://gqlgen.com/reference/scalars/
I'm having difficulty with the MarshalGQL
function. Here is the code I have so far:
package scalars
import (
"fmt"
"io"
"time"
)
type Date time.Time
// UnmarshalGQL implements the graphql.Unmarshaler interface
func (date *Date) UnmarshalGQL(value interface{}) error {
dateAsString, ok := value.(string)
if !ok {
return fmt.Errorf("date must be a string")
}
parsedTime, err := time.Parse(time.RFC3339, dateAsString)
if err != nil {
return fmt.Errorf("failed to convert given date value (%s) to Time struct", dateAsString)
}
*date = Date(parsedTime)
return nil
}
// MarshalGQL implements the graphql.Marshaler interface
func (date Date) MarshalGQL(w io.Writer) {
// This line causes a compiler error
w.Write(date.Format(time.RFC3339))
}
My issue is this line: w.Write(date.Format(time.RFC3339))
It's giving me this compiler error:
> date.Format undefined (type Date has no field or method Format) compiler (MissingFieldOrMethod)
I understand why it's saying this. The Date
type only has two functions as far as the compiler knows, UnmarshalGQL
and MarshalGQL
, both of which are declared in this file. I want to get to the time.Time
type's functions though so that I can format the date being returned. How do I go about doing this?
答案1
得分: 2
你可以按照mkopriva的建议,将Date
显式转换为time.Time
,然后进行格式化。
或者你可以通过嵌入time.Time
来创建Date
类型,这将使你可以访问time.Time
的格式化方法。
package main
import (
"fmt"
"io"
"time"
)
type Date struct {
time.Time
}
func (date *Date) UnmarshalGQL(value interface{}) error {
dateAsString, ok := value.(string)
if !ok {
return fmt.Errorf("date must be a string")
}
parsedTime, err := time.Parse(time.RFC3339, dateAsString)
if err != nil {
return fmt.Errorf("failed to convert given date value (%s) to Time struct", dateAsString)
}
*date = Date{parsedTime}
return nil
}
// MarshalGQL implements the graphql.Marshaler interface
func (date Date) MarshalGQL(w io.Writer) {
// This line causes a compiler error
w.Write([]byte(date.Format(time.RFC3339)))
}
func NewDate(v time.Time) *Date {
return &Date{v}
}
func main() {
}
为了更好地理解,你可以阅读golang-nuts
中讨论的帖子。
> 按设计,“无法在非本地类型上定义新方法”。
>
> 最佳实践是将非本地类型嵌入到自己的本地类型中,并进行扩展。类型别名(type MyFoo Foo)创建了一个与原始类型(more-or-less)完全不同的类型。我不知道有没有一种简单/最佳实践的方法可以使用类型断言来解决这个问题。
>
> Peter Bourgon
还有:
> > 类型的方法在定义它的包中。
>
> 这是一种逻辑上的一致性。这是一种编译优势。它被视为大规模维护和多人开发项目的重要优势。
>
> 你所说的能力并没有丧失,因为你可以像上面描述的那样将基本类型嵌入到新类型中,并在其中添加任何你想要的内容,以你所寻求的功能性的“is a”方式,唯一的限制是你的新类型必须有一个新的名称,并且它的所有字段和方法必须在它的新包中。
>
> Michael Jones
英文:
You can either do as mkopriva suggested to explicitly convert Date
to time.Time
and then format
or you can create Date
type by embedding time.time
which will give access to time.Time
format method
package main
import (
"fmt"
"io"
"time"
)
type Date struct {
time.Time
}
func (date *Date) UnmarshalGQL(value interface{}) error {
dateAsString, ok := value.(string)
if !ok {
return fmt.Errorf("date must be a string")
}
parsedTime, err := time.Parse(time.RFC3339, dateAsString)
if err != nil {
return fmt.Errorf("failed to convert given date value (%s) to Time struct", dateAsString)
}
*date = Date{parsedTime}
return nil
}
// MarshalGQL implements the graphql.Marshaler interface
func (date Date) MarshalGQL(w io.Writer) {
// This line causes a compiler error
w.Write([]byte(date.Format(time.RFC3339)))
}
func NewDate(v time.Time) *Date {
return &Date{v}
}
func main() {
}
For more understanding you can read golang-nuts
post which discuss this
> You "cannot define new methods on non-local type
>
> The best practice is to embed the non-local type into your own own local type, and extend it. Type-aliasing (type MyFoo Foo) creates a type that is (more-or-less) completely distinct from the original. I'm not aware of a straightforward/best-practice way to use type assertions to get around that.
>
> Peter Bourgon
And:
> > A type's methods are in the package that defines it.
>
> This is a logical coherence. It is a compilation virtue. It is seen as an important benefit for large-scale maintenance and multi-person development projects.
>
> The power you speak of is not lost, though, because you can embed the base type in a new type as described above and add whatever you want to it, in the kind of functional "is a" that you seek, with the only caveat that your new type must have a new name, and all of its fields and methods must be in its new package.
>
> Michael Jones
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论