Golang编译错误求助:如何解决常见的编译问题

Golang编译错误求助:如何解决常见的编译问题 我对Golang还比较陌生。我正在尝试实现类似于C语言中的带标签联合(tagged union)的功能。我在Go and Algebraic Data Types - Eli Bendersky’s website上找到了一些示例代码。

我认为我理解了这个示例,并尝试在我的代码中模仿它。以下是我的完整程序中引发了一个我不理解的错误的部分代码片段。在我看来,一切似乎都没问题。

package main

type Obj interface {
    isObj()
}

type Tspecial struct {
    subtype int
}

func (Tspecial) isObj() {}

func make_special(subtype int) *Obj {
	n := Tspecial{subtype}
	return &n
}

func main() {
    // dot := make_special(1)
}

使用Go版本1.19.1时,出现了以下错误:

./test.go:15:9: 无法将 &n (类型为 *Tspecial 的值) 用作返回语句中的 *Obj 类型: *Tspecial 未实现 *Obj (类型 *Obj 是指向接口的指针,而不是接口)

我认为我已经让 Tspecial 实现了 Obj,那么为什么 Tspecial 的地址不能是 *Obj 呢?

无论如何,能否有人告诉我我的错误在哪里。我相信一定有办法实现我想要的功能。


更多关于Golang编译错误求助:如何解决常见的编译问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

7 回复

嗯,你的建议编译通过了,但我无法理解为什么会这样。这在我看来非常不对劲,因为函数 make_special 声明它返回一个 Obj,而不是一个指向 Obj 的指针,而你的代码返回的是 &n,即 n 的地址,这应该是一个指向 Obj 的指针。

有人能慢慢地解释一下,或者给我指出相关文档,帮助我理解这个问题吗?我一定是遗漏了一些根本性的东西。

更多关于Golang编译错误求助:如何解决常见的编译问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


区别在于指向结构的指针和指向接口的指针。 请查看以下代码:

func writeObj(o Obj) {
	fmt.Printf("[%T] %+v\n", o, o)
}

func main() {
	a := Tspecial{1}
	var b *Tspecial = &Tspecial{2}

	writeObj(a)
	writeObj(b)
}

writeObj 可以通过接口接收一个结构体以及指向该结构体的指针,但不能接收指向接口的指针。

Go Playground - Go 编程语言

图片

package main

import "fmt"

type Obj interface {
	isObj()
}

type Tspecial struct {
	subtype int
}

func (ts *Tspecial) isObj() {}

func make_special(subtype int) Obj {
	n := Tspecial{subtype}
	return &n
}

func main() {
	dot := make_special(1)
	fmt.Println(dot)
}

当然!

  • 接口值严格来说既不是指针,也不是非指针,它只是一个接口。

Tumblr

如何在 Go 中使用接口

在我开始用 Go 编程之前,我主要使用 Python 工作。作为一名 Python 程序员,我发现学习在 Go 中使用接口极其困难。也就是说,基础知识很容易,…

谢谢你,Yamil。我现在知道如何稍微修改我的代码来让它工作了。

但是,有人能向我解释一下为什么Gonzalo的例子能工作吗?就是这个:

package main

import "fmt"

type Obj interface {
	isObj()
}

type Tspecial struct {
	subtype int
}

func (ts *Tspecial) isObj() {}

func make_special(subtype int) Obj {
	n := Tspecial{subtype}
	return &n
}

func main() {
	dot := make_special(1)
	fmt.Println(dot)
}

make_special 函数声明它返回一个 Obj,而不是一个指向 Obj 的指针,然而该函数返回的是 &n,一个指向 Tspecial(它是一个 Obj)的指针。为什么这不是一个错误?然后,回到 main 函数,Println(dot) 显示 dot&{1},这是一个指向 Tspecial 的指针。也就是说,make_special 声明它返回一个 Obj,但它显然返回了一个 *Obj

请先检查这个版本:

package main

import (
	"fmt"
	"reflect"
)

type Obj interface {
	isObj()
}

type Tspecial struct {
	subtype int
}

func (t Tspecial) isObj() {
	fmt.Println("Implementation of isObj in Tspecial")
}

func make_special(subtype int) Obj {
	n := Tspecial{subtype}
	n.isObj()
	fmt.Println(reflect.TypeOf(n))

	return n
}

func main() {
	dot := make_special(1)
	fmt.Println(dot)
	fmt.Println(reflect.TypeOf(dot))
}

它打印: isObj:Tspecial 实现 TypeOf(n)= main.Tspecial dot= {1} TypeOf(dot)= main.Tspecial

实际上,Tspecial 被视为 Obj,因为它实现了该接口所需的所有功能。 问题在于指针。指向 Tspecial 的指针和指向 Obj 的指针是两回事。

要从 make_special 返回一个 *Obj,你需要创建一个该类型的临时对象,将 “n” 转换为该类型,然后返回其指针。 类似于这样:

func make_special(subtype int) *Obj {
	n := Tspecial{subtype}
	n.isObj()
	fmt.Println(reflect.TypeOf(n))
	o := Obj(n)
	return &o
}

这是一个常见的Go语言接口使用误区。问题在于你返回的是接口指针 *Obj 而不是接口值 Obj

在Go中,接口本身已经是一个引用类型,通常不需要使用接口指针。*Obj 表示指向接口的指针,而不是指向实现了该接口的类型的指针。

以下是修正后的代码:

package main

type Obj interface {
    isObj()
}

type Tspecial struct {
    subtype int
}

func (Tspecial) isObj() {}

// 返回接口值,而不是接口指针
func make_special(subtype int) Obj {
    n := Tspecial{subtype}
    return n  // 直接返回值,不需要取地址
}

func main() {
    dot := make_special(1)
    _ = dot
}

如果你确实需要返回指针,可以这样修改:

package main

type Obj interface {
    isObj()
}

type Tspecial struct {
    subtype int
}

func (*Tspecial) isObj() {}  // 使用指针接收器

func make_special(subtype int) Obj {
    n := &Tspecial{subtype}  // 创建指针
    return n  // 返回接口值,其中包含指针
}

func main() {
    dot := make_special(1)
    _ = dot
}

关键点:

  1. 接口在Go中已经是引用类型,通常直接使用 Obj 而不是 *Obj
  2. 当方法使用指针接收器时,需要传递指针才能满足接口
  3. 接口值内部可以包含具体类型的指针

你的原始代码尝试返回 *Obj,这实际上创建了一个指向接口的指针,而不是包含具体类型指针的接口值。

回到顶部