golang 入门

一、数据类型

类型说明
布尔类型布尔类型的值只可以是常量true 或者 false
数字类型整型 int 和浮点型 float32、float64,Go 语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码
字符串类型字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本
派生类型:指针类型(Pointer)、数组类型、结构化类型(struct)、Channel类型、函数类型、切片类型、接口类型(interface)、Map类型

数字类型

类型说明
unit8无符号 8 位整型 (0 到 255)
uint16无符号 16 位整型 (0 到 65535)
uint32无符号 32 位整型 (0 到 4294967295)
uint64无符号 64 位整型 (0 到 18446744073709551615)
int8有符号 8 位整型 (-128 到 127)
int16有符号 16 位整型 (-32768 到 32767)
int32有符号 32 位整型 (-2147483648 到 2147483647)
int64有符号 64 位整型 (-9223372036854775808 到 9223372036854775807)

浮点类型

类型说明
float32IEEE-754 32位浮点型数
float64IEEE-754 64位浮点型数
float3232 位实数和虚数
float3264 位实数和虚数

其他数字类型

类型说明
byte类似 uint8
rune类似 int32
uint32 或 64 位
int与 uint 一样大小
uintptr无符号整型,用于存放一个指针

二、变量

Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字

声明变量的三种方式

使用 var 关键字声明,指定变量名称和变量类型

var v_name v_type
v_name = value
# 例:
var name string
name = "test"

# 一下几种类型不进行赋值,有自己默认值
package main

import "fmt"

func main() {
    var i int
    var f float64
    var b bool
    var s string
    fmt.Printf("%v %v %v %q\n", i, f, b, s)
}
# 输出结果:
0 0 false ""

根据值自行判断变量类型

var v_name = value
var x = "test" // 此时x 数据类型为string

省略关键字 var ,使用 := 赋值,变量类型自动判断

v_name := v_name
x := 1 //  此时x 数据类型为 int

# 测试不指定类型自动判断
package main

import (
	"fmt"
	"reflect"
)

func main() {
	x := false
	x1 := "aaa"
	x2 := 1
	x3 := 3.14
	fmt.Println("x type:", reflect.TypeOf(x))
	fmt.Println("x1 type:", reflect.TypeOf(x1))
	fmt.Println("x2 type:", reflect.TypeOf(x2))
	fmt.Println("x3 type:", reflect.TypeOf(x3))
}

# 输出结果为:
x type: bool
x1 type: string
x2 type: int
x3 type: float64

说明:声明变量时,变量名称不可重复(局部变量,即方法内部使用的变量),全局变量可以只声明不适用,局部变量声明之后必须要使用,否则编译报错(declared and not used)

在这里插入图片描述

多变量声明

//类型相同多个变量, 非全局变量
var vname1, vname2, vname3 type
vname1, vname2, vname3 = v1, v2, v3

var vname1, vname2, vname3 = v1, v2, v3 // 和 python 很像,不需要显示声明类型,自动推断

vname1, vname2, vname3 := v1, v2, v3 // 出现在 := 左侧的变量不应该是已经被声明过的,否则会导致编译错误

// 这种因式分解关键字的写法一般用于声明全局变量
var (
    vname1 v_type1
    vname2 v_type2
)

两个变量交换值

# 两个变量的数据类型必须一直才能使用
a, b = b, a

空白标识符()(用于抛弃值,比如一个函数/方法返回多个值,使用 "" 抛弃不需要的值)

package main

import "fmt"

func main() {
  _,numb,strs := numbers() //只获取函数返回值的后两个
  fmt.Println(numb,strs)
}

//一个可以返回多个值的函数
func numbers()(int,int,string){
  a , b , c := 1 , 2 , "str"
  return a,b,c
}
# 输出结果:
2 str

值类型和引用类型

值类型
所有像 int、float、bool 和 string 这些基本类型都属于值类型,使用这些类型的变量直接指向存在内存中的值。当使用等号 = 将一个变量的值赋值给另一个变量时,如:j = i,实际上是在内存中将 i 的值进行了拷贝。可以通过 &i 来获取变量 i 的内存地址,值类型的变量的值存储在栈中。
内存地址会根据机器的不同而有所不同,相同的程序在不同的机器上执行后也会有不同的内存地址。因为每台机器可能有不同的存储器布局,并且位置分配也可能不同。

引用类型
更复杂的数据通常会需要使用多个字,这些数据一般使用引用类型保存。
一个引用类型的变量 r1 存储的是 r1 的值所在的内存地址(数字),或内存地址中第一个字所在的位置。这个内存地址为称之为指针,这个指针实际上也被存在另外的某一个字中。同一个引用类型的指针指向的多个字可以是在连续的内存地址中(内存布局是连续的),这也是计算效率最高的一种存储形式;也可以将这些字分散存放在内存中,每个字都指示了下一个字所在的内存地址。当使用赋值语句 r2 = r1 时,只有引用(地址)被复制。
如果 r1 的值被改变了,那么这个值的所有引用都会指向被修改后的内容,在这个例子中,r2 也会受到影响。

三、常量

常量是一个简单值的标识符,在程序运行时,不会被修改的量,常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型

定义格式

const name [type] = value // 数据类型可以省略,编译器会自动判断
# 例:
const a string = "test"
const b = 1

# 多个常量声明
const a, b, c = v1, v2, v3

# 常量用作枚举
const (
	unknown = 0
	female = 1
	male = 2
)

常量可以用len(), cap(), unsafe.Sizeof()函数计算表达式的值。常量表达式中,函数必须是内置函数,否则编译不过

package main

import "unsafe"
const (
    a = "abc"
    b = len(a)
    c = unsafe.Sizeof(a)
)

func main(){
    println(a, b, c)
}
# 运行结果:
abc 3 16

iota

iota,特殊常量,可以认为是一个可以被编译器修改的常量。iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。

# iota 用法示例:const同时声明多个常量时,如果省略了值则表示和上面一行的值相同
# 左移:比如说 1<<2 ,把十进制 1 转成二进制,结果为 1,左移两位为 100,转成十进制为 4 (即 1*(2^2)package main

import "fmt"

func main() {
    const (
            a = iota   //0
            b          //1
            c          //2
            d = "ha"   //独立值,iota += 1
            e          //"ha"   iota += 1 (e没有进行赋值使用上一个常量的值) 
            f = 100    //iota +=1
            g          //100  iota +=1
            h = iota   //7,恢复计数
            i          //8
    )
    fmt.Println(a,b,c,d,e,f,g,h,i)
}
# 运行结果:
0 1 2 ha ha 100 100 7 8

# 左移: x<<n == x(2^n)
package main

import "fmt"
const (
    i=1<<iota // i = 1*(2^0)
    j=3<<iota // j = 3*(2^1)
    k		  // k = 3*(2^2)
    l		  // l = 3*(2^3)
)

func main() {
    fmt.Println("i=",i)
    fmt.Println("j=",j)
    fmt.Println("k=",k)
    fmt.Println("l=",l)
}
# 运行结果:
i= 1
j= 6
k= 12
l= 24

四、运算符

运算符用于在程序运行时执行数学或逻辑运算

golang 内置的运算符:

  • 算数运算符
  • 关系运算符
  • 逻辑运算符
  • 位运算符
  • 赋值运算符
  • 其他运算符

定义 a := 10,b := 20

算数运算符

运算符描述实例
+相加a + b = 30
-相减a - b = -10
*相乘a * b = 200
/相除例1: a / b = 0 例2: b / a = 2 如果结果为有余数,取整数部分
%取余数例1: b % a = 0 例2: a % b = 10
++自增a++ 结果:a为11
自减a-- 结果:a为9

自增、自减不能用来赋值,不能使用 a = a++ 和 b = b–

关系运算符

运算符描述实例
==检查两个值是否相等,如果相等返回 True 否则返回 Falsea==b 结果为 false
!=检查两个值是否不相等,如果不相等返回 True 否则返回 Falsea != b 结果为 true
>检查左边值是否大于右边值,如果是返回 True 否则返回 Falsea > b 结果为 false
<检查左边值是否小于右边值,如果是返回 True 否则返回 Falsea < b 结果为 true
>=检查左边值是否大于等于右边值,如果是返回 True 否则返回 Falsea >= b 结果为 false
<=检查左边值是否小于等于右边值,如果是返回 True 否则返回 Falsea <= b 结果为 true

逻辑运算符

定义 x := true, y := false

运算符描述实例
&&逻辑 AND 运算符。 如果两边的操作数都是 True,则条件 True,否则为 Falsex && y 结果为 false
||逻辑 OR 运算符。 如果两边的操作数有一个 True,则条件 True,否则为 Falsex // y 结果为 true
!逻辑 NOT 运算符。 如果条件为 True,则逻辑 NOT 条件 False,否则为 True!(x && y) 结果为 true

位运算符

定义 z1 : 60, z2 = 13

A = 0011 1100
B = 0000 1101
A&B = 0000 1100
A|B = 0011 1101
A^B = 0011 0001

运算符描述实例
&按位与运算符"&"是双目运算符。 其功能是参与运算的两数各对应的二进位相与(z1 & z2) 结果为 12, 二进制为 0000 1100
|按位或运算符"|"是双目运算符。 其功能是参与运算的两数各对应的二进位相或(z1 | z2) 结果为 61, 二进制为 0011 1101
^按位异或运算符"^"是双目运算符。 其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1(A ^ B) 结果为 49, 二进制为 0011 0001
<<左移运算符"<<“是双目运算符。左移n位就是乘以2的n次方。 其功能把”<<“左边的运算数的各二进位全部左移若干位,由”<<"右边的数指定移动的位数,高位丢弃,低位补0z1 << 2 结果为 240 ,二进制为 1111 0000
>>右移运算符">>“是双目运算符。右移n位就是除以2的n次方。 其功能是把”>>“左边的运算数的各二进位全部右移若干位,”>>"右边的数指定移动的位数z1 >> 2 结果为 15 ,二进制为 0000 1111

位运算符对整数在内存中的二进制位进行操作。
下表列出了位运算符 &, |, 和 ^ 的计算:

pqp & qp | qp ^ q
00000
01011
11110
10011

赋值运算符

运算符描述实例
=简单的赋值运算符,将一个表达式的值赋给一个左值C = A + B 将 A + B 表达式结果赋值给 C
+=相加后再赋值C += A 等于 C = C + A
-=相减后再赋值C -= A 等于 C = C - A
*=相乘后再赋值C *= A 等于 C = C * A
/=相除后再赋值C /= A 等于 C = C / A
%=求余后再赋值C %= A 等于 C = C % A
<<=左移后赋值C <<= 2 等于 C = C << 2
>>=右移后赋值C >>= 2 等于 C = C >> 2
&=按位与后赋值C &= 2 等于 C = C & 2
^=按位异或后赋值C ^= 2 等于 C = C ^ 2
|=按位或后赋值C |= 2 等于 C = C | 2

其他运算符

运算符描述实例
&返回变量存储地址&a 将给出变量的实际地址。
*指针变量*a 是一个指针变量

指针变量 * 和地址值 & 的区别:指针变量保存的是一个地址值,会分配独立的内存来存储一个整型数字。当变量前面有 * 标识时,才等同于 & 的用法,否则会直接输出一个整型数字

func main() {
   var a int = 4
   var ptr *int
   ptr = &a
   println("a的值为", a);    // 4
   println("*ptr为", *ptr);  // 4
   println("ptr为", ptr);    // 824633794744
}

运算符优先级

下表列出了所有运算符以及它们的优先级,由上至下代表优先级由高到低

优先级运算符
5* / % << >> & &^
4+ -
3== != < <= > >=
2&&
1||

五、条件语句

Go 没有三目运算符,所以不支持 ?: 形式的条件判断

语句描述
if由一个布尔表达式后紧跟一个或多个语句组成
if …elseif 语句 后可以使用可选的 else 语句, else 语句中的表达式在布尔表达式为 false 时执行
if嵌套可以在 if 或 else if 语句中嵌入一个或多个 if 或 else if 语句
switch用于基于不同条件执行不同动作
select类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行

if

if 布尔表达式 {
	// 当布尔表达式为true时,执行一些业务逻辑
}

# 例:
i := 8
if i > 5 {
	fmt.Printf("i 大于 5")
}

if … else

if 布尔表达式 {
	// 布尔表达式为true时,执行一些逻辑
} else {
	// 布尔表达式不为true时,执行一些逻辑
}

# 例:
s:= "success"
if s == "success" {
fmt.Printf("运行成功")
} else {
	fmt.Printf("运行失败")
}

if 嵌套

if 布尔表达式1 {
	// 布尔表达式1为true时,执行一些逻辑
	if 布尔表达式2 {
		// 布尔表达式1、2为true时,执行一些逻辑
	}
}

# 例:
i := 10
if i > 5 {
	fmt.Println("i 大于 5")
	if i < 20 {
		fmt.Println("i 小于 20")
	}
}

switch

switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上至下逐一测试,直到匹配为止
switch 语句执行的过程从上至下,直到找到匹配项,匹配项后面也不需要再加 break。
switch 默认情况下 case 最后自带 break 语句,匹配成功后就不会执行其他 case,如果我们需要执行后面的 case,可以使用 fallthrough

switch s {
	case c1 :
		// 当s 为c1时,执行一些逻辑
	case c2 :
		// 当s 为c2时,执行一些逻辑
	default :
		// 当s 不满足c1 和c2 时执行default中逻辑	
}

# 例:
// 1:男;2:女;
sex := 1
switch sex {
	case 1 :
		fmt.Println("性别:男")
	case 2 :
		fmt.Println("性别:女")
	default :
		fmt.Println("性别保密")
}

# Type Switch
# switch 语句还可以被用于 type-switch 来判断某个 interface 变量中实际存储的变量类型
# 格式:
switch x.(type){
	case type:
       statement(s);      
    case type:
       statement(s); 
    /* 你可以定义任意个数的case */
    default: /* 可选 */
       statement(s);
}
# 例:
package main

import "fmt"

func main() {
   var x interface{}
     
   switch i := x.(type) {
      case nil:  
         fmt.Printf(" x 的类型 :%T",i)                
      case int:  
         fmt.Printf("x 是 int 型")                      
      case float64:
         fmt.Printf("x 是 float64 型")          
      case func(int) float64:
         fmt.Printf("x 是 func(int) 型")                      
      case bool, string:
         fmt.Printf("x 是 bool 或 string 型" )      
      default:
         fmt.Printf("未知型")    
   }  
}
# 运行结果:
x 的类型 :<nil>

# fallthrough
# 使用 fallthrough 会强制执行后面的 case 语句,fallthrough 不会判断下一条 case 的表达式结果是否为 true
# 例:
package main

import "fmt"

func main() {

    switch {
    case false:
            fmt.Println("1、case 条件语句为 false")
            fallthrough
    case true:
            fmt.Println("2、case 条件语句为 true")
            fallthrough
    case false:
            fmt.Println("3、case 条件语句为 false")
            fallthrough
    case true:
            fmt.Println("4、case 条件语句为 true")
    case false:
            fmt.Println("5、case 条件语句为 false")
            fallthrough
    default:
            fmt.Println("6、默认 case")
    }
}
# 运行结果:
2case 条件语句为 true
3case 条件语句为 false
4case 条件语句为 true

select

select 是 Go 中的一个控制结构,类似于用于通信的 switch 语句。每个 case 必须是一个通信操作,要么是发送要么是接收。
select 随机执行一个可运行的 case。如果没有 case 可运行,它将阻塞,直到有 case 可运行。一个默认的子句应该总是可运行的。

# 语法如下:
select {
    case communication clause  :
       statement(s);      
    case communication clause  :
       statement(s);
    /* 你可以定义任意数量的 case */
    default : /* 可选 */
       statement(s);
}
  • 每个 case 都必须是一个通信
  • 所有 channel 表达式都会被求值
  • 所有被发送的表达式都会被求值
  • 如果任意某个通信可以进行,它就执行,其他被忽略。
  • 如果有多个 case 都可以运行,Select 会随机公平地选出一个执行。其他不会执行。否则:
    如果有 default 子句,则执行该语句。
    如果没有 default 子句,select 将阻塞,直到某个通信可以运行;Go 不会重新对 channel 或值进行求 值。

六、循环语句

当执行某些重复性逻辑,可以使用循环

循环类型描述
for循环重复执行语句块
循环嵌套在 for 循环中嵌套一个或多个 for 循环

for 循环

三种形式:

for init; condition; increment {
	// 执行重复性逻辑
}
init:初始化一个变量
condition:执行循环体的条件,条件满足时才进入循环体
increment:对变量的值进行增加或者减少
# 例:
package man
import "fmt"
func main() {
	for i := 0; i < 10; i++ {
		fmt.Println("hello", i)
	}
}
# init 和 increment可以省略,也可以这样写
i := 0
for ; i < 10;  {
	i += 1
	fmt.Println("hello", i)
}


for condition {
	// 当condition 条件满足,执行循环体
}
# 例:
package man
import "fmt"
func main {
	i := 0
	for i < 10 {
		i++
		fmt.Println("hello", i)
	}
}
# 不指定条件,无限循环
for {
	// 
}
# 例:
package man
import "fmt"
func main {
	i := 0
	for {
		i++
		fmt.Println("hello", i)
	}
}

for-each range 循环

这种格式的循环可以对字符串、数组、切片等进行迭代

for index, value := range 遍历的字符串/数组/切片 {
	// index为遍历对象的下标;value为下表对应的值
}

# 例:
package man
import "fmt"
func main {
	names:= []string{"小明", "小白"}
	for index, name := range names {
		fmt.Println("下标为", index, " 的姓名为:", name)
	}
}

七、函数

函数概念和定义

函数是基本的代码块,用于执行一个任务。
Go 语言最少有个 main() 函数。
你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。
函数声明告诉了编译器函数的名称,返回类型,和参数。

func function_name ([parameter_list]) [return_types] {
	// 函数体
	// func:函数由 func 开始声明
	// function_name 函数名
	// parameter_list 函数参数,0-n个
	// return_types 函数返回数据类型,0-n个
}

# 例:求和函数
func sum(n1 int, n2 int) int {
	return n1 + n2
}
# 例:返回多个参数
func swap(s1 string, s2 string) (string,string) {
	return s2,s1
}

参数传递

  • 值传递:值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数
  • 引用传递:引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数
  • 默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数。

函数闭包

Go 语言支持匿名函数,可作为闭包。匿名函数是一个"内联"语句或表达式。匿名函数可以直接使用函数内的变量,不必申明。

package main

import "fmt"
// getSequence 返回类型为函数,内部函数的作用为变量加1,并且可以直接使用局部变量 i
func getSequence() func() int {
   i:=0
   return func() int {
      i+=1
     return i  
   }
}

func main(){
   /* nextNumber 为一个函数,函数 i 为 0 */
   nextNumber := getSequence()  

   /* 调用 nextNumber 函数,i 变量自增 1 并返回 */
   fmt.Println(nextNumber())
   fmt.Println(nextNumber())
   fmt.Println(nextNumber())
   
   /* 创建新的函数 nextNumber1,并查看结果 */
   nextNumber1 := getSequence()  
   fmt.Println(nextNumber1())
   fmt.Println(nextNumber1())
}
# 运行结果:
1
2
3
1
2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值