第一篇:go之基本类型与函数使用

go之基本类型与函数使用

一、go语言介绍

1 go语言介绍

Go 即Golang,是Google公司2009年11月正式对外公开的一门编程语言,特点:语法简单,速度快。

Go是静态(编译型)强类型语言,是区别于解析型语言的弱类型语言(静态:类型固定 强类型:不同类型不允许直接运算)。

python动态强类型语言。

编译型语言:Java,c,c++,c#,go

解释性语言:python,js,php...

编译型语言涉及到跨平台问题,因为它需要编译成该平台的可执行文件。比如:java运行在jvm之上。go语言可以进行跨平台编译,即交叉编译。比如,从windows上编译成linux上的可执行文件。

解释性不涉及跨平台问题,因为各个平台有各个平台的解释器。

2 go语言特性

  • 跨平台的编译型语言,交叉编译
  • 管道(channel),切片(slice),并发(routine)
  • 有垃圾回收的机制
  • 支持面向对象和面向过程的编程模式(go的面向对象中没有类的概念,python是完全的面向对象)

3 go的历史发展

  • 2009年11月7日 weekly.2009-11-06 —— 早期的版本
  • 2015年8月19日 go1.5 —— 实现的架构变化,同时保留了和旧版本的兼容性,本次更新中移除了”最后残余的C代码”。(从此以后,自举,自己写自己)
  • 2018年8月24日 go 1.11 :增加了modules,包管理
  • 2020 年 8 月 go 1.15

4 go语言的应用领域

Google、Facebook、腾讯、七牛云

go语言书写:docker、k8s、蓝鲸...

应用领域:服务开发、并发、分布式、微服务等方向。

二、go语言开发环境

1 go环境配置

  1. IDE(Goland): 集成开发环境。
  2. 开发环境:sdk【一路下一步即可】
  3. go语言不需要手动添加到环境变量(python、java需要)
  4. go version : 打印go的版本信息

注意事项:

  1. goland创建项目:需要选择go sdk的安装路径【默认被选中】。

  2. 指定gopath:代码必须放到该路径下,否则无法执行。【默认会在环境变量中创建GOPATH,需要手动自定义进行修改】。同时,所有的go代码必须放在这个路径下的src文件夹下,否则无法执行【E:\Go_project\src\项目名】。

  3. 路径和文件都不要出现中文。

2 go常用命令

go version  // 查看go的版本信息
go env  // 查看go的环境变量
  - GO111MODULE=on  // 使用了go.mod模式
  - GOPATH=E:\Go_project  // 代码存放路径
  - GOROOT=D:\golang  // go sdk安装路径
  - ...

go build  // 编译。编译型语言,需要先编译再执行,编译成可执行文件
 - go build -o name  // 指定编译的名字
go run  // 编译并执行。两步并作一步
go clean  // 清除编译后的可执行文件

go fmt  // 格式化代码【没用】
go get  // 下载并安装包和依赖等同于pip install
...

三、第一个hello world

//单行注释
/*多行注释*/

编译型语言:
  - 编译: go build .\test01.go
  - 执行: .\test01.exe
- 编译并执行: go run .\test01.go

编译文件

windows:

  • 单个文件:go build 文件名.go
  • 多文件:go build [-o xx.exe]

linux:
单/多文件:go build *.go

直接运行文件

单个文件:
go run 文件名.go

多文件:
方式一:
编译之后,运行编译的文件
方式二:
直接运行项目名:go run E:\vscoding\gotest\

package main  // 声明包名,包名是main

import "fmt"  // 内置包

// 定义了一个main函数,go项目运行的入口【所以编译型语言必须有一个入口】
func main() {
    fmt.Println("hello world")  // 等同于python中的print(python中的print是内置函数)
}

注意:每个go文件都要有一个包名,代表其属于某个包。

goland中文件执行有file、package等几种方式。【可以自己进行配置,一般一个项目中使用package即可,测试的时候使用file就行】

四 变量

1 变量定义

  • var 变量名 变量类型 = 变量值

    var age int = 10

    go中变量定义了就必须使用,如果不适用就报错。

  • var 变量名 = 变量值 类型推导(可以不写类型)

    var age = 10

    package main
    
    import "fmt" // 内置包
    
    func main() {
        var age int = 10
        var name string = "YangYi"
        fmt.Printf("%T\n", age)  // int  (看类型,没有python中的type方法,没有自动换行,需要手动\n)
        fmt.Printf("%T\n", name)  // string
    
        fmt.Print()  // 打印不换行
        fmt.Println()  // 打印换行
        fmt.Printf("%T\n", name)  // 查看类型
        fmt.Printf("%p", &name)  // 0xc0000881e0
    }
    

    go中变量类型一旦定义,后期不能改变。(编译型语言通用,python中可以修改,python中存放的内存地址,所以可以改变类型)

  • 变量名 := 变量值 简略声明(类型和var关键字都不写)

    a := 10

    a := 10
    var a int = 100
    var a = 99  // 重复定义,报错(变量不可以重复定义,同时,变量必须先定义,后使用)
    
    /* 只定义,不赋值 */
    var a int  // 可以(只能用这种方式)
    var a  // 不可以(因为没有类型,不知道a是什么,因为类型需要在定义阶段确定,且不能改)
    
/* 声明多个变量 */
var width, height int = 100, 50  // 第一种
var width, height = 100, 50  // 第二种
width, height := 100, 50  // 第三种

var (
    name   = "YangYi"  // 不赋类型
    age  int  = 29  // 赋类型
    height int  // 声明
)
/* 小坑 */
var a int =10
// var b =99
b,a:=99,100    //这个不报错,我们觉得是重复定义,冒号左侧,只要有一个没有定义过的变量,就可以

2 变量定义规范

2.1 变量命名规范

变量命令建议用驼峰(大小写有特殊意义【私有和公有的意义】);

go文件命名建议用 下划线;(ps:python中都建议都使用下划线;java中建议都是驼峰;js中变量名驼峰)

一个名字必须以一个字母(Unicode字母)或下划线开头,后面可以跟任意数量的字母、数字或下划线;

大写字母和小写字母是不同的:Name和name是两个不同的变量;

关键字和保留字都不建议用作变量名;

2.2 go语言中的关键字

// Go语言中关键字有25个
break      default       func     interface   select
case       defer         go       map         struct
chan       else          goto     package     switch
const      fallthrough   if       range       type
continue   for           import   return      var

// Go语言中保留字有37个,主要对应内建的常量、类型和函数
内建常量: true false iota nil
内建类型:  int int8 int16 int32 int64
          uint uint8 uint16 uint32 uint64 uintptr
          float32 float64 complex128 complex64
          bool byte rune string error
内建函数: make len cap new append copy close delete
          complex real imag
          panic recover

五 数据类型

1 基础数据类型

  • 数字

    // 有符号整形
    int  //在32位机器是int32,在64位机器是int64
    int8  // 表示整数范围是:8个比特位,8个bit是1byte ,负数和0, 2的7次方-1 的范围
    int16  // 2的15次方减一
    int32
    int64
    /*
    强类型举例:
    var a int8 = 10
    var b int16 = 20
    fmt.Println(a + b)  // 报错【go是强类型,其中没有java中的自动类型转换一说】
    fmt.Println(int16(a) + b)
    */
    /*
    byte:是int8的别名  单引号包裹
    rune:是int32的别名  单引号包裹
    */
    var a byte = 99  // int8
    fmt.Println(a)
    var b byte = 'b'  // 存放的是字符,其中也是数字而已
    fmt.Println(b)  // 98
    var c rune = '你'  // 可以打印,字符中其实是数字
    fmt.Println(c)  // 20320
    var d byte = '你' 
    fmt.Println(d)  // 报错,超出范围
     
    // 无符号整形
    uint8  2的8次方减一 (定义一个人的年龄)
    uint16
    uint32
    uint64
     
    // 浮点数(小数),表示小数点后长度多少位
    float32
    float64
     
    // 复数
    complex64
    complex128
    var a complex64 = 20 + 10i
    
  • 字符串

    "双引号包裹"
    `反引号包裹`  // 和js一样; python中是 """ """
    
  • 布尔类型

    bool //true 和 false
    var flag bool = false
    var flag = true
    

数据类型默认值:数字类型是0, 字符串类型是空字符串,布尔类型是false。

java go
byte int8
short int16
int int32
long int64
float float32
double float64

2 常量

go中常量定义使用const关键字;java中的常量为final关键字;python中是大写

  • const 变量名 变量类型 = 变量值

    const name string = "yangyi"  // 常量可以定义之后不使用,不会报错
    
  • const 变量名 = 变量值

    const age = 90
    
  • 其他定义方式

    const name, age = "yangyi", 18
    const (
        name string = "yangyi"
        age = 18
    )
     
    // 应该不会使用吧
    const (
        s1 = iota
        s2
        s3 = iota
        s4 = 99
        s5
    )
    fmt.Println(s1)  // 0
    fmt.Println(s2)  // 1
    fmt.Println(s3)  // 2
    fmt.Println(s4)  // 99
    fmt.Println(s5)  // 99 太奇怪
     
    const (
        s1 = iota
        s2
        s3 = iota
        s4 = 99
        s5 = iota
    )
    fmt.Println(s1)  // 0
    fmt.Println(s2)  // 1
    fmt.Println(s3)  // 2
    fmt.Println(s4)  // 99
    fmt.Println(s5)  // 4 太奇怪
    

六 函数

1 函数基础

func 函数名(参数名 类型, 参数名 类型)(返回值类型, 返回值类型){
    函数体内容
    return 返回值1, 返回值2
}

函数使用示例

// 1 有参数无返回值
func add(a int, b int){
    fmt.Println(a + b)
}

add(100, 200)  // 调用函数 

// 2 有参数无返回值,有多个相同类型的参数
func add(a, b int){
    fmt.Println(a + b)
}

// 3 有参数无返回值,有多个不同类型的参数
func add(a, b int, msg,name string){
}

// 4 多个参数,一个返回值
func add(a, b int) int {
    return a + b
}

// 5 多个参数,多个返回值【python和go支持多返回值】
func add (a, b int) (int, int){
    return a + b, a * b
}

a, b := add(100, 200)  // 多返回值就需要用多变量进行接受【和python一样】
a, _ := add(3, 4)  // python中的下划线可以打印,但是go中就是空

// 6 命令返回值
func add(a, b int) (c int, d int){
    c = a + b  // 就是在函数体中已经声明了c d的变量
    d = a * b 
    return  // 就会直接将c d返回出去,不需要写 return c,d
}

2 函数高级

函数是一等公民,函数可以赋值给变量【python中也是如此】

在编译型语言中,和解释性语言不同,没有先定义函数,后使用函数一说,编译之后都能找到。

// 匿名函数(定义在函数内部,不能有名字): python中是lamdba
// 第一种
func (){ 
}()  // 匿名函数直接调用

// 第二种
var a func()  // 定义一个变量,类型为func()【哈哈】
a = func(){  // 此时a是一个函数   
    fmt.Println("我是匿名函数")
}
a()  // 我是匿名函数
// 7 函数返回值为函数
func test() func(){
    return func(){
        fmt.Println("我是返回的函数...")
    }
}
a := test()
fmt.Println(a)  // 0x5451e0 【打印函数名,拿到的还是函数的内存地址】


// 8 返回值函数,返回的函数带参数
// 返回值类型必须跟返回的函数类型匹配 即 func()和func(msg string)不是一个类型
func test() func(msg string){  // 返回值类型必须跟返回的函数类型匹配
    return func(msg string){
        fmt.Println("我是返回的函数...")
    }
}

a := test()
a("hello")  // 函数调用

// 9 函数返回值为函数,返回的函数带参数,带返回值
func test() func(a, b int) int {
    return func(a, b int) int {
        return a + b
    }
}

a := test()  // a的类型为 var a func(a, b int)int
fmt.Println(a(2, 3))

// 10 函数参数为函数类型,返回值为带参数带返回值的函数类型
func test(f func()) func(a, b int) (int, int){
    f()  // f函数执行
    return func(a, b int) (int, int){
        f()  // f函数执行
        return a + b, a * b
    }
}

// 函数操作
a, b := test(
    func(){
        fmt.Println("我是函数参数...")
    },
)(3, 4)  // 函数调用

// 或者
f := func(){
    fmt.Println("我是函数参数...")
}
f1 := test(f)
a, b := f1(3, 4)
fmt.Println(a, b)

3 闭包函数

①定义在函数内部; ②对外部作用域有引用; 【可以实现C++函数中的static关键字功能】

闭包函数其实就是多了一种对函数传参的方式。

func test(age int) func() {
    // age := 18 
    a := func(){  // 定义在函数内部
        fmt.Println(age)  // 对外部作用域有引用
    }
    return a
}

a := test(19)
a()  // 闭包函数的调用【并没有传参,实际上已经有参数传递进去】

// 一般来说,函数执行完毕,参数应该被释放,但是由于闭包函数的存在,所以age一直没有被释放,有东西对其有引用。【引出内存逃逸: 正常应该被回收,其实没有被回收】

// 装饰器是闭包函数的典型应用(go语言中没有装饰器的语法糖,python中有语法糖)

4 type类型重命名

type MyFunc func()  // 类型重命名
func test() MyFunc  {
    return func(){
    }
}

type MyFunc func(a,b int)(int,string)
func test() MyFunc  {
    return func(a,b int)(int,string) {
        fmt.Println("xxx")
        return 10,"ok"
    }
}

type Myint int  // 这里Myint和int已经不是一个类型了
var a int = 10
var b Myint = 100
fmt.Println(a + b)  // 报错
fmt.Println(a + int(b))  // 强制类型转换

5 变量的作用域范围

同一个包下,函数名不能重名。比如:都在main包中

// 第一种方式
var a int   //全局变量,全局有效,只要改了,就是改了【python修改全局变量,需要添加global】
func main() {
    fmt.Println(a)  //0
    a=19
    fmt.Println(a) //19
    test1()  //99
    fmt.Println(a) //99
}

func test1()  {
    a=99
    fmt.Println(a)  // 99
}

// 第二种方式【局部 ——> 全局 ——> 内置】
var a int   //全局变量,全局有效,只要改了,就是改了
func main() {
    var a int
    fmt.Println(a)  //0
    a = 19
    fmt.Println(a) //19
    test1()  // 0
    fmt.Println(a) //19
}

func test1()  {
    fmt.Println(a)
}
posted @ 2023-04-03 20:38  YangYi215  阅读(41)  评论(0编辑  收藏  举报