Golang中结构体与函数的应用指南
Golang中结构体与函数的应用指南 对比老师的代码 https://play.golang.org/p/AKrvuxF0wMK
和我的代码 https://play.golang.org/p/11zv6VD–y7
我哪里做错了? 错误信息中的"undefined"是什么意思? 我该怎么做?
谢谢。现在越来越清晰了。
我只是在说明这个区别,但你说得对,这种命名方式确实不符合惯例,本可以取得更好。谢谢。
我认为在名称中使用类型并不符合惯例。可以使用 verified、result 或 res 来代替 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个作用域:函数作用域和两个嵌套的内部作用域。同时,注释展示了变量在这些作用域中的可见性规则。如你所见,花括号本身就可以创建作用域,它们不需要是 if、function 等语句的一部分。所以使用时请小心。
在您的代码中,出现"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
关键点:
- 函数调用必须在函数体内(如main函数内)
- 结构体方法需要通过结构体实例调用
- 普通函数可以直接调用,但需要传递所需参数


