包
  每个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, "")
}
我试了一下,确实如此,谢谢啦[抱拳]