Golang 入门系列(五)GO语言中的面向对象

前面讲了很多Go 语言的基础知识,包括go环境的安装,go语言的语法等,感兴趣的朋友可以先看看之前的文章。https://www.cnblogs.com/zhangweizhong/category/1275863.html

今天GO语言中的面向对象。

 

GO语言中的面向对象

 

其实GO并不是一个纯面向对象编程语言。它没有提供类(class)这个关键字,只提供了结构体(struct)类型。

java或者C# 里面,结构体(struct)是不能有成员函数的。然而,Go语言中的结构体(struct)可以有”成员函数”。方法可以被添加到结构体中,类似于一个类的实现。

我个人觉得Go 语言在的面向对象,其实更简单,也更容易理解。

 

学过java或C# 的人应该都知道,面向对象的三个基本特征:封装、继承和多态。他们的定义我这里就不细说了。下面,就直接看看 go 语言下的面向对象是怎样实现的吧。

 

1. 封装特性

Golang区分公有属性和私有属性的机制就是方法或属性是否首字母大写,如果首字母大写的方法就是公有的,如果首字母小写的话就是私有的。

复制代码
package main

import "fmt"

type Person struct {
    name string
}

func (person *Person) setName(name string) {
    person.name = name
}

func (person *Person) GetInfo() {
    fmt.Println(person.name)
}

func main() {
    p := Person{"zhangsan"}
    p.setName("lisi")
    p.GetInfo()
}
复制代码

 

2. 继承特性

GO语言的继承方式采用的是匿名组合的方式:Woman 结构体中包含匿名字段Person,那么Person中的属性也就属于Woman对象。

复制代码
package main

import "fmt"

type Person struct {
    name string
}

type Woman struct {
    Person
    sex string
}

func main() {
    woman := Woman{Person{"wangwu"}, "女"}
    fmt.Println(woman.name)
    fmt.Println(woman.sex)
}
复制代码

 

3. 多态特性

复制代码
package main

import "fmt"

type Eater interface {
    Eat()
}

type Man struct {
}

type Woman struct {
}

func (man *Man) Eat() {
    fmt.Println("Man Eat")
}

func (woman *Woman) Eat() {
    fmt.Println("Woman Eat")
}

func main() {
    var e Eater

    woman := Woman{}
    man := Man{}

    e = &woman
    e.Eat()

    e = &man
    e.Eat()
}
复制代码

 

最后

以上,就把Go语言如何实现面向对象的简单介绍了一下,其实跟java和C# 等也都差不多,大家可以比较着来看。总结的来说就是:Go没有类,而是松耦合的类型、方法对接口的实现。

 

Golang 入门系列(四)如何理解interface接口

前面讲了很多Go 语言的基础知识,包括go环境的安装,go语言的语法等,感兴趣的朋友,可以先看看之前的文章。https://www.cnblogs.com/zhangweizhong/category/1275863.html

今天就正式开始写Go 的代码,讲讲如何理解interface接口。

 

1. 什么是interface接口

interface 是GO语言的基础特性之一。可以理解为一种类型的规范或者约定。它跟java,C# 不太一样,不需要显示说明实现了某个接口,它没有继承或子类或“implements”关键字,只是通过约定的形式,隐式的实现interface 中的方法即可。因此,Golang 中的 interface 让编码更灵活、易扩展。

如何理解go 语言中的interface ? 只需记住以下三点即可:

1. interface 是方法声明的集合
2. 任何类型的对象实现了在interface 接口中声明的全部方法,则表明该类型实现了该接口。
3. interface 可以作为一种数据类型,实现了该接口的任何对象都可以给对应的接口类型变量赋值。

 

注意:
a. interface 可以被任意对象实现,一个类型/对象也可以实现多个 interface
b. 方法不能重载,如 eat() eat(s string) 不能同时存在

2. 接口实现

复制代码
package main

import "fmt"

type Phone interface {
    call()
}

type NokiaPhone struct {
}

func (nokiaPhone NokiaPhone) call() {
    fmt.Println("I am Nokia, I can call you!")
}

type ApplePhone struct {
}

func (iPhone ApplePhone) call() {
    fmt.Println("I am Apple Phone, I can call you!")
}

func main() {
    var phone Phone
    phone = new(NokiaPhone)
    phone.call()

    phone = new(ApplePhone)
    phone.call()
}
复制代码

 

3. interface 查询

如果接口A实现了接口B中所有方法,那么A可以转化为B接口。

 if varName2, ok := varName1.(interface2|typeName); ok {
    //此时 varName2 的类型由 interface1 转为 interface2,或者 varName1 不是 typeName 类型的变量
  } else {
    //不能转换 interface,或者 varName1 不是 typeName 类型的变量

 

4. interface{} 类型

  interface{} 类型没有声明任何一个方法,俗称空接口。interface{} 在我们需要存储任意类型的数值的时候相当有用,有点类似于C语言的void*类型。

复制代码
package main

import (
    "fmt"
)

func PrintAll(vals []interface{}) {
    for _, val := range vals {
        fmt.Println(val)
    }
}

func main() {
    names := []string{"stanley", "david", "oscar"}
    vals := make([]interface{}, len(names))
    for i, v := range names {
        vals[i] = v
    }
    PrintAll(vals)
}
复制代码

然而,需要注意的是,[]T不能直接赋值给[]interface{}

        t := []int{1, 2, 3, 4}
        var s []interface{} = t

编译时会输出下面的错误:

cannot use t (type []int) as type []interface {} in assignment

 

最后

以上,对Go 语言中的接口特性做了一个简单的介绍。我觉得对于go语言来说,设计最精妙的应该是interface了,感兴趣的,可以好好研究研究。

 

Golang 入门系列(三)Go语言基础知识汇总

前面已经了 Go 环境的配置和初学Go时,容易遇到的坑,大家可以请查看前面的文章 https://www.cnblogs.com/zhangweizhong/category/1275863.html

在这篇文章中,下面为初学者汇总下Go语言基础知识:

 

1. Go 程序的基本结构

下面是一个Go 程序的基本结构,包含(包声明,引入包,函数等)

复制代码
package main // 定义包名,package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。

import "fmt" // 导入需要使用的包(的函数,或其他元素)

func main() { // 程序的入口函数。main 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数。
  fmt.Println("Hello, World!")
}
复制代码

 

2. 数据类型

go内建基本数据类型包括基本数据类型和高级数据类型

1. 基本数据类型
布尔类型(bool)

数值类型

整数类型(byte,rune,int/uint,int8/uint8,int16/uint16,int32/uint32,int64/uint64)
浮点类型(float32,float64)
复数类型(complex64,complex128)

字符串类型
string Go的字符串是由单个字节连接起来的。使用UTF-8编码标识Unicode文本。

2. 高级数据类型

数组(array)
切片(slice)
字典(map)
通道(channel)
函数(function)
结构体(function)
接口(interface)
指针(*Xxx,Pointer,uintptr)

如果按照底层结构划分,值类型包括(所有基本数据类型,数组,结构体),引用类型包括(slice,map,channel,function,interface,指针)

3. 变量&常量

1. 变量名由字母、数字、下划线组成,其中首个字母不能为数字,例:var name string
2. 声明
a.指定变量类型,声明后若不赋值,使用默认值。
var name string
name = “李四”

b.根据值自行判定变量类型。
var name = “李四”

c.简短形式,省略var, 注意
age := 10

注意
(:=)是使用变量的首选形式
(:=)只能被用在函数体内,而不可以用于全局变量的声明与赋值。
(:=)左侧的变量不应该是已经声明过的,否则会导致编译错误。

3. 常量的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。
1. 常量声明:const b string = “abc”
2. iota,特殊常量
const (
a = iota
b
c
)

1. 代表连续的,无类型的整数常量,
2. 以const开始的常量声明语句为单位,
3. 从0开始,没赋给一个常量就递增一次
4. 一旦跨越以const开始的常量声明语句就归0

4. 运算符
1. 算术运算符,a + b ,包括(+,-,*,/,%,++,–)
2. 关系运算符,返回True或False ,a == b ,包括(==,!=,>,<,>=,<=)
3. 逻辑运算符,返回True或False ,包括(&&,||,!)
4. 地址运算符

& : 返回变量存储地址 (&originalValue)

* :指针变量 (*pointerValue)

5. 接收运算符,用于接收通道的数据或者给将数据加入通道(intChan<-1, <-intChan)

5. 错误处理

1. error 接口,(errors.New(value),fmt.Error(),自定义错误类型)

复制代码
func Divide(a, b float64) (result float64, err error) {
    if b == 0 {
        result = 0.0
        err = errors.New("runtime error: divide by zero")
        return
    } else {
        result = a / b
        err = nil
    }
    return
}
复制代码

2. panic 函数,panic(value) 与error 接口联用,

    var user = os.Getenv("USER")
    if user == "" {
        panic("The USER environment variable is not set.")
    }

 

3. recover 函数,与defer语句联用,

复制代码
func TestB() (err error) {
    defer func() { //在发生异常时,设置恢复
        if x := recover(); x != nil {
            err = fmt.Errorf("internal error: %v", x)
        }
    }()

    panic("func TestB(): panic")
}
复制代码

 

6. Go 基本命令

go build 命令主要是用于测试编译。在包的编译过程中,若有必要,会同时编译与之相关联的包。

go run hello.go

go get 命令主要是用来动态获取远程代码包的。

go get github.com/go-sql-driver/mysql

go run 命令主要用于编译并运行Go程序。

go run hello.go

go test 命令,会自动读取源码目录下面名为*_test.go的文件,生成并运行测试用的可执行文件。

 

Golang 入门系列(二)Go语言基础语法及需要注意的坑

上一章节我们已经了解了 Go 环境的配置,不了解的,请查看前面的文章 https://www.cnblogs.com/zhangweizhong/p/9459945.html,本章节我们将学习 Go 语言的基础语法中需要注意的点。

 

GO语言基础语法

go 的基础语法,我这里就不细说了,大家可以查看这个文章,学习Go 详细的语法:http://www.runoob.com/go/go-basic-syntax.html

最好是对照上面的例子,一个一个敲出来,这样效果最好。

下面是一个Go 程序的基本结构,包含(包声明,引入包,函数等)

package main   // 定义包名,package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。

import "fmt"   // 导入需要使用的包(的函数,或其他元素)

func main() {  // 程序的入口函数。main 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数。
   fmt.Println("Hello, World!")
}

 

GO语言注意的坑

不管学啥,刚开始都会遇到各种各样的坑。下面就来总结下学习go语言的过程中,遇到的各种坑。

1. 写C# 的人都会将 “{” 独立一行,但是这在go 里面是错误的 “{” 必须更方法体 在同一行。我第一次写go 的就犯了这个错误,还不知道错误在哪。

func main() {
   fmt.Println("Hello, World!")
}

 

2. if…else 语句中的 else 必须和 if 的 ’ } ’ 在同一行,否则编译错误

 var a int = 30

 if a < 20 {
    fmt.Print("a<20")
 } else {
    fmt.Print("a>=20")
 }

 

2. 包名的定义。你必须在源文件中非注释的第一行声明包名,如:package main。package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。

package main

 

3. 在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,因为这些工作都将由 Go 编译器自动完成。

如果你打算将多个语句写在同一行,则必须使用 ; 人为区分,但在实际开发中我们并不鼓励这种做法。

fmt.Println("Hello, World!")
fmt.Println("www.fpeach.com")

 

3. main()函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数。然而,每个package 中,只能有一个main() 函数,否则会报main redeclared in this block previous declaration at .. 的错误。

 package main

import “fmt”

func main() {
   /* 这是我的第一个简单的程序 */
   fmt.Println("Hello, World!")
}

 

4. 当函数、结构等标识符以一个大写字母开头,如:GetInfo,那么使用这种形式的标识符的对象就可以被外部包的代码所使用,这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected )。

// 公有函数,可以被外部包的代码所使用
func Test() {
   .
   .
   .
}

// 私有函数,包的内部是可见、
func test2() {
   .
   .
   .
}

 

5. 标识符用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母(A~Z和a~z)数字(0~9)、下划线_组成的序列,但是第一个字符必须是字母或下划线而不能是数字。

以下是无效的标识符:

  • 1ab(以数字开头)
  • case(Go 语言的关键字)
  • a+b(运算符是不允许的)

 

6. 错误 no new variables on left side of := ,意思是,“左边一个新的变量也没有!”

func main() {
    var b int = 20
    b := 30
    fmt.Print(b)
}

解决办法就是:对于x,y:=….这种形式,只要把其中的一个变量命名成新的就可以了。

 

7. 不能使用++自增或- -自减运算符初始化变量和对变量赋值

package main

import "fmt"

func main(){
    var a int = 10
    var b int = a++

    var c int = 20
    c = a++

    fmt.Print(a, b, c)
}

 

Golang 入门系列(一)Go环境搭建

安装 Go

Go语言的优劣,这里就不介绍了,下面直接讲Go 的安装:

Go 的官方网站http://golang.org/(需要FQ软件)

国内下载地址http://www.golangtc.com/download

下载对应平台的安装包。注意区分32位还是64位操作系统。

安装包下载完成之后,安装过程很简单,傻瓜式下一步到底就好了。

 

Go 环境变量

安装go 的时候,安装程序会自动把相关目录写到系统环境。但是如果是zip 的安装,需要自己手动添加。

主要配置以下几个:

  • GOROOT:Go 安装后的根目录(例如:D:\Go),安装过程中会由安装程序自动写入系统环境变量中。
  • GOBIN:Go 的二进制文件存放目录(%GOROOT%\bin)
  • PATH:需要将 %GOBIN% 加在 PATH 变量的最后,方便在命令行下运行。

当环境变量都配置完成之后,Go 就已经安装完毕了。打开命令行,运行 go 命令,就可以看到如下的提示了。

Go 工作空间

GOPATH : Go 的工作空间,就是我们的开发和依赖包的目录(例如:我的是 D:\Go_Path\go) ,此目录需要手动配置到系统环境变量

GOPATH 工作空间是一个目录层次结构,其根目录包含三个子目录:

  • src:包含 Go 源文件,注意:你自己创建依赖的package,也要放到GOPATH 目录下,这样才能够被引用到。
  • pkg:包含包对象,编译好的库文件
  • bin:包含可执行命令

注意:

1. 需要将GOPATH 路径,手动写入到系统环境变量。

2. 不要把 GOPATH 设置成 Go 的安装路径

3. 你自己创建依赖的package,也要放到GOPATH 目录下,这样才能够被引用到。

 

配置好之后,通过 go env 命令来查看go环境是否配置正确:

 

Hello World

现在,一起来 Hello World 吧!

复制代码
package main
import (
    "fmt"
)

func main() {
    fmt.Println("Hello World!") 
}
复制代码

 

将上面的程序保存成 helloworld.go,然后在命令行中执行:

go run helloworld.go

 

其他

1. IDE 的下载安装这里就不说,大家直接去这个地址下载就行。

Goland下载链接:https://www.jetbrains.com/go/download/#section=windows

2. 我用的是Atom 编辑器。配置有点麻烦,不建议大家使用。

3. 后面直接讲Go语言的如何使用。

4. 能翻的最好FQ,因为很多package 在golang官网,不FQ下载不下来。