包
每个package就是一个包.包是源码的集合.任何代码文件必须属于某个包.并且代码文件第一行有效代码必须是package 包名
来声明下面代码所属的包.
注意事项
- 每个目录只能有一个包.
- 包名不需和目录名一样
- main包为可执行入口,必须要有main函数
- 结构体的方法必须在同一个包内
使用演示
以上一篇面向接口中的组合接口代码进行演示.完整代码如下.接下来进行拆分
package main
import (
"fmt"
"io"
"io/ioutil"
"os"
)
type IWriter interface {
// 传入写文件的名字以及内容
write(filename, content string) string
}
type IReader interface {
// 传入要读取文件的内容
read(filename string) string
}
type IAdminer interface {
// 包含两个接口
IWriter
IReader
}
type qvbilam struct{}
func (qvb qvbilam) read(filename string) string {
content, rErr := ioutil.ReadFile(filename)
if rErr != nil {
fmt.Println(rErr)
return "读取文件错误"
}
return string(content)
}
func (qvb qvbilam) write(filename, content string) string {
// 创建文件
file, err := os.Create(filename)
if err != nil {
fmt.Println(err)
return "创建文件出错"
}
// 打开文件
_, writeErr := io.WriteString(file, content)
if writeErr != nil {
fmt.Println(writeErr)
return "写入文件出错"
}
return "写入文件成功"
}
func main() {
// 实例化结构
qstr := qvbilam{}
// 定义读接口的变量.结构体为qvbilam
var qint IAdminer = qstr
// 进行读
res := qint.read("basic/2.txt")
// 将读的内容写入
result := qint.write("basic/3.txt",res)
fmt.Println(result)
}
抽离结构体
创建file/Model/qvbilam.go
.内容如下:
package Model
import (
"fmt"
"io"
"io/ioutil"
"os"
)
type qvbilam struct{}
func (qvb qvbilam) read(filename string) string {
content, rErr := ioutil.ReadFile(filename)
if rErr != nil {
fmt.Println(rErr)
return "读取文件错误"
}
return string(content)
}
func (qvb qvbilam) write(filename, content string) string {
// 创建文件
file, err := os.Create(filename)
if err != nil {
fmt.Println(err)
return "创建文件出错"
}
// 打开文件
_, writeErr := io.WriteString(file, content)
if writeErr != nil {
fmt.Println(writeErr)
return "写入文件出错"
}
return "写入文件成功"
}
抽离接口
创建file/Interface/interface.go
内容如下
package Interface
type IWriter interface {
// 传入写文件的名字以及内容
write(filename, content string) string
}
type IReader interface {
// 传入要读取文件的内容
read(filename string) string
}
type IAdminer interface {
// 包含两个接口
IWriter
IReader
}
创建入口
创建file/main.go
内容如下
package main
import (
"fmt"
)
func main() {
// 实例化结构
qstr := qvbilam{}
// 定义读接口的变量.结构体为qvbilam
var qint IAdminer = qstr
// 进行读
res := qint.read("basic/2.txt")
// 将读的内容写入
result := qint.write("basic/3.txt",res)
fmt.Println(result)
}
无法实例化结构体:因为结构体的包没有引入.在goland编译器中只需在实例化结构体qvbilam{}
前加上目录名.编译器会自动引入包.
// 编译器自动添加file/Model
import (
"file/Model"
"fmt"
)
// main函数中实例化结构体修改
qstr := Model.qvbilam{}
修改后还是无法使用,提示Unexported type 'qvbilam' usage
.这是因为在go语言中.首字母小写代表private,首字母大写代表public
,修改file/Model/qvbilam.go
.将结构体首字母改为大写,同样在主函数调用的时候也要改成首字母大写.结构体部分代码如下:
// 结构体首字母大写
type Qvbilam struct{}
// 方法内的结构体首字母同样大写
func (qvb Qvbilam) read(filename string) string {
...
}
无法实现接口:在main函数中通过var qint Interface.IAdminer = qstr
提示Cannot use 'qstr' (type Qvbilam) as type Interface.IAdminer in assignment Type cannot implement 'Interface.IAdminer' as it has a non-exported method and is defined in a different package
.同理是方法名首字母没有大写.将接口,结构体主函数的方法名都改为大写即可.
完整代码
接口:file/Interface/interface.go
package Interface
type IWriter interface {
// 传入写文件的名字以及内容
Write(filename, content string) string
}
type IReader interface {
// 传入要读取文件的内容
Read(filename string) string
}
type IAdminer interface {
// 包含两个接口
IWriter
IReader
}
结构体:file/Model/qvbilam.go
package Model
import (
"fmt"
"io"
"io/ioutil"
"os"
)
// 结构体首字母大写
type Qvbilam struct{}
// 方法内的结构体首字母同样大写
func (qvb Qvbilam) Read(filename string) string {
content, rErr := ioutil.ReadFile(filename)
if rErr != nil {
fmt.Println(rErr)
return "读取文件错误"
}
return string(content)
}
func (qvb Qvbilam) Write(filename, content string) string {
// 创建文件
file, err := os.Create(filename)
if err != nil {
fmt.Println(err)
return "创建文件出错"
}
// 打开文件
_, writeErr := io.WriteString(file, content)
if writeErr != nil {
fmt.Println(writeErr)
return "写入文件出错"
}
return "写入文件成功"
}
入口:file/main.go
package main
import (
"file/Interface"
"file/Model"
"fmt"
)
func main() {
// 实例化结构
qstr := Model.Qvbilam{}
// 定义读接口的变量.结构体为qvbilam
var qint Interface.IAdminer = qstr
// 进行读
res := qint.Read("basic/2.txt")
// 将读的内容写入
result := qint.Write("basic/3.txt",res)
fmt.Println(result)
}
面向对象
注意事项
对于权限访问,如public,private等关键字,在go中是没有的.通过上述的举例中可以看到,首字母大写为public
可以在其他包中使用,首字母小写为private
,只可在本包中使用.不可在其他包内调用.
封装
在go中是没有类的概念的.可以把结构体想象成类.例如定义一个人,每个人都有身高和体重,使用结构体进行封装如下:
type Human struct{
stature int
weight int
}
继承
同样没有关键字extends
,可以在结构体定义匿名类型.如下:
定义匿名接口
type People struct {
name string
age int
}
type Worker struct {
People // 类型为People结构体,没有名
sex int
}
使用
初始化People后传入到Work1中,打印结果是不同的,重构成员属性.
func main() {
hj := People{"郝建",32}
Worker1 := Worker{hj,32}
//worker2 := Worker{People{"QvBiLam",16},1}
Worker1.name = "郝建2"
fmt.Println(Worker1.name)
fmt.Println(hj.name)
}
如需要再修改Woker1的同时也将People的属性修改则可以使用指针.如下打印结果是相同的.
type People struct {
name string
age int
}
type Worker struct {
// 添加*使用指针
*People // 类型为People结构体,没有名
sex int
}
func main() {
hj := People{"郝建",32}
// 传入&hj
Worker1 := Worker{&hj,32}
//worker2 := Worker{People{"QvBiLam",16},1}
Worker1.name = "郝建2"
fmt.Println(Worker1.name)
fmt.Println(hj.name)
}
多态
不同对象中对同一种行为的不同实现方式,定义一个动作接口,其中包含,Say
方法.定义Human
,Dog
结构体对Say
的实现.
定义接口
// 定义动作接口
type Action interface {
// 返回字符串类型
Say() string
}
定义Human结构体
// 定义人类结构体
type Human struct {}
// 实现接口
func (h Human) Say() string{
return "Hello"
}
定义Dog结构体
// 定义狗结构体
type Dog struct {}
// 实现接口
func (d Dog) Say() string{
return "Wang Wang Wang"
}
使用演示
getType
函数返回类型为动作接口,只要是实现了接口的结构体就可以返回使用.获取不同结构体的同种方法.只需要修改getType
中的结构体即可,降低代码耦合性.
// 获取结构体,返回类型为 动作接口
func getType() Action{
//return Human{}
return Dog{}
}
func main() {
// 调用方法获取结构体
aType := getType()
// 定义动作接口类型,值为结构体
var action Action = aType
// 调用Say
fmt.Print(action.Say())
}
讲解很详细,学习到了
谢谢博主,看您的文章解决了“it has a non-exported method and is defined in a different package”问题。但是没太搞懂,使用命令 protoc -I ./*.proto --go_out=plugins=grpc:./自动生成的*.pb.go文件中,函数名称就是mustEmbedUnimplementedXXX()开头就是小写的,但是自己实现的时候函数名称就要大写(MustEmbedUnimplementedXXX())否则一直提示上面的错误
你这个留言好像不在对应的文章里啊。。。
不需要自己实现mustEmbedUnimplementedXXX 函数; 可以使用匿名函数UnimplementedCategoryServer
例如
type CategoryServer struct {
proto.UnimplementedCategoryServer
}
func (s *CategoryServer) Create(ctx context.Context, request *proto.UpdateCategoryRequest) (*proto.CategoryResponse, error) {
return nil, status.Error(codes.Unimplemented, "")
}
我试了一下,确实如此,谢谢啦[抱拳]
加油