go学习(三、面向对象)

文章目录

    • 3.1 结构体和方法
      • 3.1.1 结构体定义和使用
      • 3.1.2 方法定义
      • 3.1.3 值接受者vs 指针接收者
    • 3.2 包和封装
      • 3.2.1 封装
      • 3.2.2 包
      • 3.2.3 示例
      • 3.2.4 扩展别人的类型
    • 3.3 GOPATH学习
      • 3.3.1 GOPATH环境变量
      • 3.3.2 go命令

3.1 结构体和方法

go语言仅支持封装,不支持继承和多态。

go更没有c++的虚函数啥的。

所以go只有struct,没有class,这个倒是有点像c。

3.1.1 结构体定义和使用

type TreeNode struct {
    Left, Right *TreeNode
    Value int
}


func main() {

    node := TreeNode{Value : 3}                // 这个只赋值了value
    node.Right = &TreeNode{}                // 这是建了一个空结点
    node.Left = &TreeNode{nil, nil, 5}        // 可以省略字段,直接按顺序赋值
    node.Right.Left = new(TreeNode)            // 当然也是可以使用new的

    nodes := []TreeNode {                   // 定义一个结构体切片
        {Value : 3},
        {},
        {nil, &node, 6},
    }
    fmt.Println(nodes)

}

go语言没有构造函数,这个感觉是因为go只支持struct的,不支持类,struct只又变量,所以变量可以赋初值就可以了。

当然如果想自己写构造函数,那就跟c语言一样,写一个工厂函数,返回一个类对象。

func creatNode(value int) *TreeNode {
    return &TreeNode{Value : value}
}

这种玩法,让我想起了当初用c语言来搞面向对象,就是这种感觉。

注意:如果按c++的标准,这个是返回了局部变量,c++的局部遍历是存储在栈上的,返回指针是有问题的,但是go语言不存在这个问题,因为go语言根据程序员的写法,自动推断这个变量是存储在栈上还是堆上。

3.1.2 方法定义

接下来我们看看go的struct的方法怎么定义:

func (node TreeNode) println() {
    fmt.Println(node)
}

把类型定义在前面,这个在go语言中的说法是接收者,也就是我调用的时候:

node.println()    // node对象会传给这个println函数,printfln函数会接收这个node对象

这种方式是值接收者,是不可以修改对象中的值的,只有指针接收者才能修改变量的值:

func (node *TreeNode) setValue(value int) {
    node.Value = value
}

看着其实问题不大,就改成一个指针。

其他语言的接收者,也就是this指针,其实都是传指针,只有go语言支持两个。

注意:go语言nil是可以调用的,只不过是取不到值的

var pRoot *TreeNode
pRoot.setValue(33)     // 这是可以执行的,调用到函数内部的,需要在函数内部判断


func (node *TreeNode) setValue(value int) {
    if node == nil {     // 这里加判断就可以了
        return 
    }
    node.Value = value
}

如果是c++语言的话,需要在指针调用的时候,就需要判断了。

3.1.3 值接受者vs 指针接收者

  • 要改变内容必须使用指针接收者

  • 结构过大也考虑使用指针接收者

  • 一致性:如有指针接收者,最好都是指针接收者

3.2 包和封装

3.2.1 封装

  • 名字一般使用CamelCase(驼峰法)

  • 首字母大写:public (公有方法或变量)

  • 首字母小写:private (私有方法或变量)

3.2.2 包

  • 每个目录一个包(包名和目录名可以不一样,但是一个目录只能有一个包)

  • main包包含可执行入口(其他包可以写main函数么,可以试试)

  • 为结构定义的方法必须放在同一个包内(可以多文件,但一定要在一个包内)

3.2.3 示例

package main

import (
    "./node"        // 包的引入,是引入文件夹,这个要记住
)

func main() {        // main包的mian函数才是执行的开始

    node := tree.TreeNode{Value : 3}                // 这个只赋值了value
    node.Right = &tree.TreeNode{}                // 这是建了一个空结点
    node.Left = &tree.TreeNode{nil, nil, 5}        // 可以省略字段,直接按顺序赋值
    node.Right.Left = new(tree.TreeNode)            // 当然也是可以使用new的
    node.Right.Right = tree.CreatNode(2)

    node.Println()
    node.SetValue(66)
    node.Println()

    var pRoot *tree.TreeNode
    pRoot.SetValue(33)
}

这是tree包

package tree

import (
    "fmt"
)

func CreatNode(value int) *TreeNode {
    return &TreeNode{Value : value}
}

type TreeNode struct {
    Left, Right *TreeNode
    Value int
}

func (node TreeNode) Println() {
    fmt.Println(node)
}

func (node *TreeNode) SetValue(value int) {
    if node == nil {
        return 
    }
    node.Value = value
}

func main() {                                // 确实可以在其他包写main函数,就相当是一个测试用例,但是不知道怎么编译的,好像没有mian包编译不了,可以先写成main包,然后在修改成单独的包

    node := TreeNode{Value : 3}                // 这个只赋值了value
    node.Right = &TreeNode{}                // 这是建了一个空结点
    node.Left = &TreeNode{nil, nil, 5}        // 可以省略字段,直接按顺序赋值
    node.Right.Left = new(TreeNode)            // 当然也是可以使用new的
    node.Right.Right = CreatNode(2)

    node.Println()
    node.SetValue(66)
    node.Println()

    var pRoot *TreeNode
    pRoot.SetValue(33)
}

总结两点:包引入记得是文件夹名,包的文件名可以跟包名不一样。

3.2.4 扩展别人的类型

如果是其他语言,扩展别人类型,是可以通过继承的方式来扩展。

因为go语言没有继承,所以我们来看看go语言是怎么扩充别人的类型。

  • 定义别名

    使用别名,就难了一点点

    // 使用别名
    type queue []int       // 用type来定义[]int别名
    
    func (q *queue) push(value int) {    // 封装好了就各种操作
    	*q = append(*q, value)
    }
    
  • 使用组合

    组合的方式比较简单

    // 这个我们来扩展一个tree
    type myTree struct {
    	node *tree.TreeNode
    }
    
    func (myNode *myTree) printf() {
    	myNode.node.Println()
    }
    

3.3 GOPATH学习

3.3.1 GOPATH环境变量

  • 默认在~/go(unix,linux),%USERPROFILE%\go(windows)

  • 官方推荐:所有项目和第三方库都放在同一个GOPATH下

  • 也可以将每个项目放在不同的GOPATH

3.3.2 go命令

go get 获取第三方库 (用这个命令可以获取到github上的包)

gopm get -v 路径 (这个命令可以获取谷歌网站的包)

go build 来编译

go install 产生pkg文件和可执行文件

go run直接编译运行

你可能感兴趣的:(go学习,golang,学习,go面向对象)