Golang中结构体与函数的应用指南

Golang中结构体与函数的应用指南 对比老师的代码 https://play.golang.org/p/AKrvuxF0wMK

和我的代码 https://play.golang.org/p/11zv6VD–y7

我哪里做错了? 错误信息中的"undefined"是什么意思? 我该怎么做?

19 回复

哎呀,“{”

更多关于Golang中结构体与函数的应用指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


谢谢。现在越来越清晰了。

我只是在说明这个区别,但你说得对,这种命名方式确实不符合惯例,本可以取得更好。谢谢。

我正在尝试添加一些if条件语句。
https://play.golang.org/p/4p14PYiHLUv
我需要帮助

我认为在名称中使用类型并不符合惯例。可以使用 verifiedresultres 来代替 ageStr

iegomez:

对第一个内部作用域不可见 fmt.Println(sa2)

不确定你所说的"可见"是什么意思。

您的话让我明白了自己的问题所在。我是这样解决的:

package main

import (
	"fmt"
)

func main() {
	fmt.Println("Hello, playground")
}

那里涉及多个错误。我认为你需要通过仔细阅读和理解错误信息来开始解决它们。如果我们帮你把所有错误都修复了,你将永远无法从容应对错误,而且这些错误并不特别难以理解。

“方法尖叫”? “你看到这行代码有什么不同?” 与什么相比的不同? 你是在说这里…“func yourFunc() { //错误 }” 意思是"{"不能与"func yourFunc() {"放在代码的不同行?

我仍然不明白你为什么要创建所有这些作用域,它们并不是必需的。

我稍微重构了你的代码,移除了那些作用域,并"验证"客户是否未满18岁:https://play.golang.org/p/96V_0VnqglS

你没有定义 person 类型,这就是它未定义的原因(原始代码在第7-10行定义了 person 类型)。这个错误信息在这种情况下非常明确。总之,只需将 clients 类型重命名为 person,或者在验证类型中嵌入 clients 而不是 person

但我无法理解为什么函数体缺失。这难道不是函数体吗?

“func main()” 好的,我通过在 “func main()” 后面加上 “}” 解决了那个问题

现在我遇到这个问题:https://play.golang.org/p/0JQCbmJekcc 错误提示说 age 未定义。但我以为我在这里已经定义了它:“age int”

https://play.golang.org/p/EaCljefDKTH

这段代码能够运行,但未能实现我的目标:让程序检查年龄,如果未满18岁,则输出…

我想我对自己想要实现的功能还不够明确。我希望程序能根据客户是否年满18岁来判断其验证状态:年满18岁则标记为已验证,未满18岁则标记为未验证。

cherilexvold1974:

“method scream” ?

我是指编译器会提示存在错误,在这个例子中会显示 age 未定义。

cherilexvold1974:

“What difference do you see with this line?” Difference from what?

你发布的代码中抛出错误的那一行,和我回复中写的代码有什么区别?

cherilexvold1974:

Are you saying here…“func yourFunc() { //wrong }” that “{” can’t be on a different line in the code than “func yourFunc() {”

完全正确。

我正在探索。 https://play.golang.org/p/96V_0VnqglS 这看起来非常有趣,我正在研究它。我想我现在已经了解到"ageStr"是一个随机名称,但"Str"这个部分有什么特殊含义吗? "c.age"也是随机的吗? 从后续内容来看,"c.“似乎具有某种重要性。 “%s is a %s, is %d and so %s.\n” 这看起来很有意思,虽然我不确定它的具体含义。 我从goDoc了解到%s表示"字符串或切片的未解释字节”。

如果您愿意进一步解释,我会非常感兴趣。可能我在这里有点钻牛角尖了,所以如果您认为应该等我进一步学习后再继续讨论,请直说。

这意味着它尚未被声明,因此不能在该作用域内使用。例如,如果在函数中声明了一个局部变量,该变量只能在该函数内使用或可见,因此其他函数无法引用它:

func f() {
  a := 1
  fmt.Println(a)
}

func g() {
  fmt.Println(a) // 这行代码无效,a在此作用域内不可见
}

正如我之前提到的,花括号会创建作用域,因此这也适用于它们。所以,以下代码同样无效:

func someFunc(){
...
  {
    a := 1
    fmt.Println(a) // 这行代码有效
  }
  fmt.Println(a) // 这行代码无效,a在此处不可见
}

cherilexvold1974:

我现在明白了,“ageStr” 是个随机名称,还是说 “Str” 这部分有什么特殊含义?

这里的"随机"是指你可以为标识符选择任何其他名称。在这个例子中我称它为 ageStr,因为它是一个包含年龄相关信息的字符串,我想明确区分 client 结构体的 age 字段和这个字符串。

cherilexvold1974:

“c.age” 也是随机的吗?

在什么意义上是随机的?你是在问 c 是否随机吗?在这种情况下,Go 鼓励使用简短的接收器名称,所以使用结构体首字母来命名接收器是很常见的做法。

cherilexvold1974:

“%s is a %s, is %d and so %s.\n” 这看起来很有趣,虽然我不确定它的含义。

这些是格式动词,它们控制在打印时内容的格式化方式。更多细节请查看:fmt 包 - fmt - Go 包

你将其定义为 clients 类型的字段,该字段嵌入在 verification 类型中。所以想一想,为什么在方法内部调用 age 会报错 undefined?你觉得这行代码有什么不同?

fmt.Println("V", s.first, s.age, s.occupation)

另外,关于函数体缺失的问题:Go语言有严格的格式规则,其中规定(除单行函数外)函数应该这样定义:

func yourFunc() {
  // 代码
}

这意味着这种格式(或任何不符合正确格式的写法)是无效的:

func yourFunc()
{
  //错误
}

另外需要注意的是,你在那里创建了一些奇怪且不必要的作用域。如果你通过添加 {} 来修复主函数,那么你会得到以下代码:

func main() {
//函数作用域
	{
        //第一个内部作用域
		sa1 := verification{
			clients: clients{
				"Terry",
				25,
				"forklift",
			},
			verified: true,
		}
		{
            //第二个内部作用域
			sa2 := verification{
				clients: clients{
					"Kevin",
					17,
					"student",
				},
				verified: false,
			}
			fmt.Println(sa1)
			fmt.Println(sa2)
			sa1.status()
			sa2.status()

		}
        //这里会报错,因为sa2在第二个内部作用域中声明,对第一个内部作用域不可见
       fmt.Println(sa2)
	}
    //这里会报错,因为sa1在第一个内部作用域中声明,对函数作用域不可见
    fmt.Println(sa1)
}

如注释所述,这里有3个作用域:函数作用域和两个嵌套的内部作用域。同时,注释展示了变量在这些作用域中的可见性规则。如你所见,花括号本身就可以创建作用域,它们不需要是 iffunction 等语句的一部分。所以使用时请小心。

在您的代码中,出现"undefined"错误是因为您尝试在main函数之外直接调用add函数,但Go语言不允许在函数体外执行函数调用。让我通过示例代码来解释正确的做法。

首先,这是您代码的问题部分:

package main

import "fmt"

type calc struct {
    a, b int
}

func (c calc) add() int {
    return c.a + c.b
}

// 错误:不能在函数体外直接调用函数
add()

正确的做法应该是:

package main

import "fmt"

type calc struct {
    a, b int
}

// 方法定义
func (c calc) add() int {
    return c.a + c.b
}

// 也可以定义普通函数
func add(a, b int) int {
    return a + b
}

func main() {
    // 使用方法
    c := calc{a: 5, b: 3}
    result1 := c.add()
    fmt.Println("使用方法的结果:", result1)
    
    // 使用函数
    result2 := add(5, 3)
    fmt.Println("使用函数的结果:", result2)
    
    // 或者直接创建匿名结构体调用方法
    result3 := calc{a: 10, b: 20}.add()
    fmt.Println("匿名结构体的结果:", result3)
}

"undefined"错误的具体含义:

  • 当编译器显示"undefined: add"时,意味着在当前作用域中找不到名为add的标识符
  • 在您的代码中,虽然定义了add方法,但单独写add()会被当作函数调用,而不是方法调用

结构体与函数的正确应用:

package main

import "fmt"

// 定义结构体
type Calculator struct {
    x, y int
}

// 为结构体定义方法
func (c Calculator) Multiply() int {
    return c.x * c.y
}

func (c Calculator) Divide() float64 {
    if c.y == 0 {
        return 0
    }
    return float64(c.x) / float64(c.y)
}

// 独立的函数
func Subtract(a, b int) int {
    return a - b
}

func main() {
    // 创建结构体实例
    calc := Calculator{x: 15, y: 3}
    
    // 调用结构体方法
    fmt.Println("乘法:", calc.Multiply())
    fmt.Println("除法:", calc.Divide())
    
    // 调用独立函数
    fmt.Println("减法:", Subtract(15, 3))
    
    // 修改结构体字段值后再次调用方法
    calc.x = 20
    calc.y = 4
    fmt.Println("修改后的乘法:", calc.Multiply())
}

输出:

乘法: 45
除法: 5
减法: 12
修改后的乘法: 80

关键点:

  1. 函数调用必须在函数体内(如main函数内)
  2. 结构体方法需要通过结构体实例调用
  3. 普通函数可以直接调用,但需要传递所需参数
回到顶部