How to instantatiate struct from the string representation of the struct name

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

How to instantatiate struct from the string representation of the struct name

问题

在Go语言中,可以使用反射(reflect)来动态实例化结构体。以下是你提供的代码的翻译:

// convert_image.go

var converters = map[string]string{
  "png":  "PngConverter",
  "jpg":  "JpegConverter",
  "jpeg": "JpegConverter",
}

type Converter interface {
  convert(*bytes.Buffer) string
}

func selectConverter(converterName string) {
  // 使用反射动态初始化转换器
}

func ConvertImageToWords(filename string, image *bytes.Buffer) string {
  ext := Ext(filename)
  if converterName, ok := converters[ext]; ok {
    converter := selectConverter(converterName)
    id := converter.convert(image)
  }

  return nil
}

// converters/png_converter.go

type PngConverter struct {}

func (converter PngConverter) convert(in *bytes.Buffer) string {
  // ...
}

// converters/jpeg_converter.go

type JpegConverter struct {}

func (converter JpegConverter) convert(in *bytes.Buffer) string {
  // ...
}

希望这可以帮助到你!如果你有任何其他问题,请随时问我。

英文:

Does go allow you to instantiate a struct from a string? (similar to https://stackoverflow.com/questions/3464007/ruby-convert-class-name-in-string-to-actual-class in Ruby)

I am trying to separate code from a single file into subdirectories but was getting undefined: PngConverter when running go build. It may have been a load order issue however now I'm trying to dynamically instantiate the struct.

convert_image.go

var converters = map[string]string{
  "png": "PngConverter",
  "jpg": "JpegConverter",
  "jpeg": "JpegConverter",
}

type Converter interface {
  convert(*bytes.Buffer) string
}

func selectConverter(converterName string) {
  // dynamically initialize the converter with reflect?
}

func ConvertImageToWords(filename string, image *bytes.Buffer) string {
  ext = Ext(filename)
  if converterName, y := converters[ext]; y {
    converter = selectConverter(converterName)
    id = converter.convert(image)
  }

  return nil
}

converters/png_converter.go

type PngConverter struct {}

func (converter PngConverter) convert(in *bytes.Buffer) string {
  // ...
}

converters/jpeg_converter.go

type JpegConverter struct {}

func (converter JpegConverter) convert(in *bytes.Buffer) string {
  // ...
}

答案1

得分: 1

动态评估

Go是一种编译语言,这意味着没有动态评估,一切都在编译之后完成。而解释型语言如Ruby、Python或Javascript具有用于动态编程的eval(和类似的)函数,这在编译语言中在概念上是不可能的。

接口作为一种惯用的抽象方式

如果你需要在Go中使用泛型类型,毫无疑问地使用接口。你非常接近正确的方法:你不需要通过字符串来评估一个结构体,而是应该声明一个Converter interface类型的对象映射,其中包含所有必需的实现。

可编译的 playground

var converters map[string]Converter

type Converter interface {
    convert(*bytes.Buffer) string
}

type PngConverter struct{}
type JpgConverter struct{}

func (p *PngConverter) convert(b *bytes.Buffer) (repr string) { return }
func (p *JpgConverter) convert(b *bytes.Buffer) (repr string) { return }

func ConvertImageToWords(
        filename string,
        image *bytes.Buffer,
        converters map[string]Converter) (repr string) {
    ext := Ext(filename)
    if converter, y := converters[ext]; y {
        repr = converter.convert(image)
    }

    return
}

导入和包

虽然没有人问,但这是错误的设计:

> 是的,它们在不同的目录中...

包是一个命名空间,你可以在其中拥有多个文件,而不需要将每个文件都导入到另一个文件中。包是一个包含package <name>作为第一行的go文件的目录。但是,如果你将不同的文件分开放置在不同的包(目录)中,如果你需要在另一个包中使用它,你需要导入它。类似Java的类模块设计对于Go来说是不正确的。只需将所有的转换器和接口放在同一个包中即可。

英文:

Dynamic evaluation

Go is compiling language it means there is no dynamic evaluation, everything is done after compilation. Interpreting languages like Ruby, Python or Javascript has eval (and analogs) functions for dynamic programming which is conceptually impossible for compiling languages.

Interfaces as an idiomatic way of abstraction

If you need a generic type in Go - use interface <strike>with no doubt</strike>. Also you are very close to a correct approach: you don't need to evaluate a struct from string instead of it you should declare a map of object of Converter interface types with all required implementations.

Compilable playground:

var converters map[string]Converter

type Converter interface {
    convert(*bytes.Buffer) string
}

type PngConverter struct{}
type JpgConverter struct{}

func (p *PngConverter) convert(b *bytes.Buffer) (repr string) { return }
func (p *JpgConverter) convert(b *bytes.Buffer) (repr string) { return }

func ConvertImageToWords(
        filename string,
        image *bytes.Buffer,
        converters map[string]Converter) (repr string) {
    ext := Ext(filename)
    if converter, y := converters[ext]; y {
        repr = converter.convert(image)
    }

    return
}

Import and packages

You haven't been asked but this is wrong design:

> Yes, they're in a separate directories...

Package is a namespace where you can have multiple files and you don't need to import each of them to another. Package is a directory with go files containing package &lt;name&gt; as a first line. But if you separated files with different packages (directories) you need to import it if you need to use it in another package. Java-like class-module design is not correct for Go. Just keep all your converters and the interface in the same package.

答案2

得分: 0

不,你不能从字符串表示中初始化一个结构体。

你可以在ConvertImageToWords函数中传递接口。

func ConvertImageToWords(conv Converter, image *bytes.Buffer) string

或者在ConvertImageToWords函数内部将文件名转换为Converter接口。

func GetConverter(ext string) Converter {
  switch ext {
    case "png":
      return PngConverter{}
    case "jpg":
   ...
}

func ConvertImageToWords(filename string, image *bytes.Buffer) string {
  ext := Ext(filename)
  conv := GetConverter(ext)
  id := conv.convert(image)
  ...
}

另外,最好将接口方法导出:

type Converter interface {
  Convert(*bytes.Buffer) string
}

参考链接

参考链接

英文:

No, you can't initialize a struct from String representations.

Reference

What you can do is pass the interface in ConvertImageToWords.

func ConvertImageToWords(conv Converter, image *bytes.Buffer) string

Or have the filename converted to interface Converter within ConvertImageToWords.

func GetConverter(ext string) Converter {
  switch ext {
    case &quot;png&quot;:
      return PngConverter{}
    case &quot;jpg&quot;:
   ...
}

func ConvertImageToWords(filename string, image *bytes.Buffer) string {
  ext = Ext(filename)
  conv := GetConverter(ext)
  id := conv.convert(image)
  ...
}

Also it's better to have the interface method exported :

type Converter interface {
  Convert(*bytes.Buffer) string
}

Reference

huangapple
  • 本文由 发表于 2017年3月9日 15:56:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/42689697.html
匿名

发表评论

匿名网友

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

确定