话接上文
如果各位童鞋想要获得下面的源码,请搜索gzh:隔壁王小猿,关注后回复“Go语言基本语法”即可获得
面向对象
结构体与方法
- Go语言仅支持封装,不支持多态和继承
- Go语言没有class,只有struct
结构体的创建
- 不论地址还是结构本身,一律使用 . 来访问
- Root:=treeNode{value:3}
- Root.left=&treeNode{}
- Root.right=&treeNode{5,nil,nil}
- Root.right.left=new(treeNode)
- 示例
var root treeNode
fmt.Println(root)
root = treeNode{
value: 3,
right: &treeNode{},
left: &treeNode{}}
fmt.Println(root)
root.left = &treeNode{5, nil, nil}
fmt.Println(root)
root.right.left = &treeNode{}
fmt.Println(root)
fmt.Println(root.left)
fmt.Println(root.right)
nodes := []treeNode{
{value: 3},
{right: &treeNode{}},
{value: 5, left: &treeNode{5, nil, nil}},
{3, nil, new(treeNode)}}
fmt.Println(nodes)
输出
{0 <nil> <nil>}
{3 0xc000004500 0xc0000044e0}
{3 0xc000004540 0xc0000044e0}
{3 0xc000004540 0xc0000044e0}
&{5 <nil> <nil>}
&{0 0xc000004580 <nil>}
[{3 <nil> <nil>} {0 <nil> 0xc000004620} {5 0xc000004640 <nil>} {3 <nil> 0xc000004600}]
工厂函数-模拟构造函数
- 返回的局部地址
func createNode(value int) *treeNode {
return &treeNode{value: value}
}
给结构体定义方法
- 显示定义和命名方法的接收者
- 使用指针作为方法接收者
- 只有使用指针才可以改变结构内容
- nil指针也可以调用方法
- 示例
type treeNode struct {
value int
left, right *treeNode
}
func (node treeNode) printValue() {
fmt.Println(node.value)
}
//值传递 不会更改值
func (node treeNode) setValue(value int) {
node.value = value
}
//指针传递 会更改值
func (node *treeNode) setValuePointer(value int) {
node.value = value;
}
func createNode(value int) *treeNode {
return &treeNode{value: value}
}
var root treeNode
root.value = 3
root.left = &treeNode{}
root.right = &treeNode{5, nil, nil}
root.right.left = new(treeNode)
root.left.right = createNode(2)
fmt.Println("root value:")
root.printValue()
root.right.left.setValue(4)
fmt.Println("root.right.left value:")
root.right.left.printValue()
root.right.left.setValuePointer(4)
fmt.Println("root.right.left value:")
root.right.left.printValue()
输出
root value:
3
root.right.left value:
0
root.right.left value:
4
值接收者vs指针接收者
- 要改变内容必须使用指针接收者
- 结构过大也考虑使用指针接收者
- 一致性,如果有指针接收者,最好都是指针接收者
- 值接收者是go语言特有的
- 值、指针接收者均可接收值、指针
包&封装
- Go语言通过名字来区分public和private
- 名字一般使用CamelCase
- 首字母大写 public
- 首字母小写 private
包
- 每个目录一个包
- mian包包含可执行入口
- main函数所在目录只能有一个main包
- 为结构定义的方法必须在同一个包内,可以是不同文件
包-扩充系统类型或者别人的类型
- 定义别名
- 使用别名myTreeNode封装TreeNode
type myTreeNode struct {
node *tree.TreeNode
}
//后续遍历
func (myNode *myTreeNode) postOrder() {
if myNode == nil || myNode.node == nil {
return
}
//指针不能作为接收者, 需要需要定义变量来接送地址
//myTreeNode{myNode.node.Left}.postOrder();
left := myTreeNode{myNode.node.Left}
left.postOrder()
right := myTreeNode{myNode.node.Right}
right.postOrder()
myNode.node.PrintValue()
}
var root tree.TreeNode
root.Value = 3
root.Left = &tree.TreeNode{}
root.Right = &tree.TreeNode{5, nil, nil}
root.Right.Left = new(tree.TreeNode)
root.Left.Right = tree.CreateNode(2)
//root.Traverse()
pRoot := myTreeNode{&root}
pRoot.postOrder()
输出
2
0
0
5
3
- 使用组合
- 使用int组合实现queue
package queue
type Queue []int
func (q *Queue) Push(v int) {
*q = append(*q, v)
}
func (q *Queue) Pop() int {
if q == nil {
panic("error.")
}
head := (*q)[0]
*q = (*q)[1:]
return head
}
func IsEmpty(q *Queue) bool {
return len(*q) == 0
}
GOPATH环境变量
- 默认~/go(linux,unix), %USERPROFILE%\go(windows)
- 官方推荐:所有项目和第三方库都放在一个GOPATH下
- 也可以将每个项目放在不同的GOPATH
- Go get 命令获取包,也可以用gopm获取
- GOPATH下目录结构
- Src
- Git rep1
- Git rep2
- Pkg
- Git rep1
- Git rep2
- Bin
- 可执行文件
面向接口
duck typing
先问一个比较考三观的问题:图片中的大黄鸭,它是不是一只鸭子呢?
Duck Typing 的原话是,走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么它就是一只鸭子。
这个原话是可以灵活理解的,就看我们怎么定义鸭子的行为,我们可以说,能浮在水上游的,黄色的,可爱的就是鸭子,那么,图片中的大黄鸭,它就是一只鸭子!
这就是所谓的 Duck Typing,它只关心事物的外部行为而非内部结构。它并不关心你这只鸭子是长肉的还是充气的。
Python中duck typing
Def download(retriever):
Return retriever.get(“www.baidu.com”)
- 运行时才知道传入的retriever有没有get
- 需要注释来说明接口
C++中的duck typing
Template<class R>
Def download(const R& retriever){
Return retriever.get(“www.baidu.com”);
}
- 编译时才知道传入的retriever有没有get
- 需要注释来说明接口
Java中类似代码
<R extends Retriever >
String download(R r){
Return r.get(“www.baidu.com”);
}
- 传入的参数必须实现Retriever接口,编写代码过程中就知道必须包含get方法
- 不是duck typing
Go语言中的duck typing
- 同时可以实现多个接口
- 具有python和c++ 的duck typing的灵活性
- 又具有Java的类型检查
- 类似duck typing
接口
- Go语言接口是由使用者定义的
接口的定义
type Retriever interface {
Get(url string) string
}
接口的实现
- 接口的实现是隐式的
type Retriever struct {
Context string
}
func (r Retriever) Get(url string) string {
return r.Context
}
接口变量里面有什么
- 接口变量自带指针
- 接口变量同样采用值传递,几乎不需要使用接口的指针
- 指针接收者实现只能以指针方式使用,值接收者都可
查看接口变量
- 表示任何类型:interface{}
- Type Assertion
- Type Switch
接口组合
type getItf interface {
Get(url string) string
}
type postItf interface {
Post(url string, from map[string]string) string
}
type getAndPostI interface {
getItf
postItf
}
面向函数
闭包
func adder() func(int) int {
sum := 0
return func(v int) int {
sum += v
return sum
}
}
func main() {
a := adder();
for i := 0; i < 10; i++ {
fmt.Println(a(i))
}
}
adder函数返回的是一个闭包,不仅仅是一个函数,还包含sum的引用等