每个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())
}
Last modification:March 27th, 2020 at 11:29 am