Go语言 如何要求一个特定的构造函数?

vfh0ocws  于 2023-09-28  发布在  Go
关注(0)|答案(2)|浏览(74)

我想为可序列化对象定义一个接口。在我的上下文中,serializable意味着对象可以转换为字符串,字符串可以转换为对象。

type Serializable interface {
    Format() string
    Parse(string) Serializable
}

显然这是错误的,因为这指定Parse应该是一个方法,尽管它必须是一个构造函数。
如何要求一个类型可以在Go中以特定的方式构造?

kzipqqlq

kzipqqlq1#

Go语言没有明确的构造函数概念,因为没有好的构造函数语法。但是有一种方法可以强制包的用户使用您定义的方法之一来构造接口。
要做到这一点,你只需在接口中包含一个私有方法:

package mypkg

type Serializable interface {
    Format() string
    serialize()
}

type serializer struct {
    fmt string
}

func (s *serializer) Format() string {
    return s.fmt
}

func (s *serializer) serialize() {}

func Parse(fmt string) Serializable {
    return &serializer{
        fmt: fmt,
    }
}

尝试从包外部实现Serializable,如下所示:

package main

import (
    "github.com/m/example/mypkg"
)

func main() {
    abc := NewAbc()
    abc.Format()
}

type Abc struct {}

func (a *Abc) Format() string {
    return "abc"
}

func (a *Abc) serialize() {}

func NewAbc() mypkg.Serializable {
    return &Abc{}
}

导致cannot use &Abc{} (value of type *Abc) as mypkg.Serializable value in return statement: *Abc does not implement mypkg.Serializable (missing method serialize)错误,即使serialize被定义为方法。因为它没有被导出,所以mypkg包看不到它,所以它不能满足接口,从而保证用户将需要使用提供的构造函数之一。

kd3sttzy

kd3sttzy2#

如果我正确理解了这个问题,你可以尝试使用generics来参数化Serializable接口:

type Serializable[T any] interface {
    Format() string
    Parse(val string) Serializable[T]
}
type A struct {
    Val string
}

func (a A) Format() string {
    b, _ := json.Marshal(a)
    return string(b)
}

func (a A) Parse(val string) Serializable[A] {
    var res A
    _ = json.Unmarshal([]byte(val), &res)
    return a
}

然后创建特定的构造函数:

func NewSerializableA(val string) Serializable[A] {
    return A{Val: val}
}

PLAYGROUND

相关问题