Go 基础语法 轻松上手 goland~

2023-09-16 16:41:40

一个GO代码,hello,world

说到学习语言,那必然少不了我们的hello world了,先来看个简单的hello world代码

package main  
  
import "fmt"  
  
func main() {  
fmt.Println("hello, world")  
}
  1. 第一行代码 package main 定义了包名。你必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main。package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。
  2. 下一行 import “fmt” 告诉 Go 编译器这个程序需要使用 fmt 包(的函数,或其他元素),fmt 包实现了格式化 IO(输入/输出)的函数。

是不是感觉有点 java + c 的味道?笑
学过 java 的应该都知道println是输出并换行,这里好像无非就是把system.out换成了fmt,并且需要导入fmt这个包
然后又综合了python,句末不需要写分号, 并且if elsefor后不需要加括号
但是这里需要注意的是,他这个括号还就必须这样打了,不能单独打一行
例如:

在这里插入图片描述


接下来是go的一些基础语法

Go标识符

Go的标识符和c一样,是由字母、数字、下划线组成,并且第一个字符必须是字母或下划线,而不能是数字。


GO关键字

breakdefaultfuncinterfaceselect
casedefergomapstruct
chanelsegotopackageswitch
constfallthroughifrangetype
continueforimportreturnvar

除了以上的关键字,go语言还有36个预定义标识符

appendboolbytecapclosecomplexcomplex64complex128uint16
copyfalsefloat32float64imagintint8int16uint32
int32int64iotalenmakenewnilpanicuint64
printprintlnrealrecoverstringtrueuintuint8uintptr

GO运算符

与c++基本一致,需要注意的就是go的++和–不能参与运算,所以++和–也是只能放在变量的后面

在这里插入图片描述


GO语言注释

和c++一样, //注释单行, /* .... */ 注释多行


GO的变量与常量声明

变量:var + name + type = value 或者 name := value

使用 := 的话go就会自动推导类型,所以两种方式实际上是一样的,所以要注意前者不能和后者混用

注意 : := 符号只允许在函数中使用,即只能在声明局部变量的时候使用,而 var 没有这个限制。

例如:

package main  
  
import "fmt"  
  
func main() {  
    var a int = 3  
    fmt.Println(a)  
    b := 4  
    fmt.Println(b)  
}

输出结果为:

3
4

下面这样就是错误的

在这里插入图片描述

下面这样也是错误的

在这里插入图片描述

另外,还可以一次声明多个变量并且赋值

package main  
  
import "fmt"  
  
func main() {  
    var a, b, c int = 3, 4 ,5  
    fmt.Println(a, b, c)  
}

常量:const + name + type = value

例如:

package main  
  
import "fmt"  
  
func main() {  
    const a int = 3  
    fmt.Println(a)  
}

常量之后不能进行值的改变,不然就会报错

在这里插入图片描述

同样也可以一次声明多个值

package main  
  
import "fmt"  
  
func main() {  
    const a, b, c int = 3, 4, 5  
    fmt.Println(a, b, c)  
}

GO语言基本语句

if else

与c++类似,也支持嵌套。不同的是if后面的表达式不需要写括号,并且if后面一定要跟大括号,建议根据以下格式规范写。

if 布尔表达式 {
   /* 在布尔表达式为 true 时执行 */
} else {
  /* 在布尔表达式为 false 时执行 */
}

例如:

func main() {  
    a := 100  
    if a >= 100 {  
    fmt.Println(">=100")  
    } else {  
    fmt.Println("<100")  
    }  
}

switch语句

也与c++类似,但是这里的case默认自带break,也就是在成功执行一个case之后就会跳出,c++是遇到一个符合条件的case之后会一直执行后面case的语句直到遇到break才会停止。

switch var1 {
case value1:
    ...
case value2:
    ...
default:
    ...
}

例如:

package main  
  
import "fmt"  
  
func main() {  
    score := 'A'  
    switch score {  
    case 'A':  
        fmt.Println("太棒了")  
    case 'B':  
        fmt.Println("继续加油")  
    case 'C':  
        fmt.Println("要努力哦")  
    default:  
        fmt.Println("下次加油哦")  
    }     
}

结果为:

太棒了

fallthrough

想要实现c++的效果,可以使用fallthrough,其实c++也有这玩意儿就是了

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

package main  
  
import "fmt"  
  
func main() {  
    score := 'A'  
    switch score {  
    case 'A':  
        fmt.Println("太棒了")  
        fallthrough  
    case 'B':  
        fmt.Println("继续加油")  
        fallthrough  
    case 'C':  
        fmt.Println("要努力哦")  
        fallthrough  
    default:  
        fmt.Println("下次加油哦")  
    }  
}

结果为:

太棒了
继续加油
要努力哦
下次加油哦

for循环

go语言中没有while,但是能用for循环实现while的效果,基本用法也与c++相似。

下面是一个简单的for循环:

for i := 1; i <= 5; i++ {  
    fmt.Println(i)  
}

可以通过以下方式实现while的效果:

func main() {  
    n := 5  
    for n > 0 {  
        n--  
        fmt.Println(n)  
    }  
}

可以这样实现无限循环:

for {  
    n--  
    fmt.Println(n)  
}

要停止无限循环,可以在命令窗口按下ctrl-c

For-each range

这种格式的循环可以对字符串、数组、切片、map等进行迭代输出元素。
这里要注意,遍历的时候,字符串、数组、切片这些有序的要用两个值,第一个是下标,第二个才是value。无序的map也要用两个值,一个是key,一个是value。同样也是不需要的值不使用就行了, 不想用的值可以使用_代替

例如:

package main  
  
import "fmt"  
  
func main() {  
  
    s := "may all the beauty blessed"  
    strs := [3]string{"A", "B", "C"}  
    slice := []int{1, 2, 3}  
    map1 := map[int]string{  
        0: "48",  
        1: "49",  
        2: "50",  
    }  
    for i, c := range s {  
        fmt.Print(i, string(c))  
        fmt.Print(" ")  
    }  
    fmt.Println()  
    for _, s := range strs {  
        fmt.Print(s)  
        fmt.Print(" ")  
    }  
    fmt.Println()  
    for i, num := range slice {  
        fmt.Print(i, num)  
        fmt.Print(" ")  
    }  
    fmt.Println()  
    for key, value := range map1 {  
        fmt.Print(key, value)  
        fmt.Print(" ")  
    }  
}

输出结果为:

0m 1a 2y 3  4a 5l 6l 7  8t 9h 10e 11  12b 13e 14a 15u 16t 17y 18  19b 20l 21e 22s 23s 24e 25d
A B C
0 1 1 2 2 3
048 149 250
// 前面的0,1, 2...是下标啊

这里还发现了print,类型相同会分开,类型不同不会分开,qwq


GO语言数据类型

Go是一种强类型语言
总共有四大类

  • 基础类型
  • 聚合类型
  • 引用类型
  • 接口类型

image.png

基础类型

基础类型与c语言类似,
有分为int, uint, float, complex, string, bool

int:

在这里插入图片描述

uint:

在这里插入图片描述

uintptr与unsafe.Pointer

这个uintptr是啥呢?这个牵扯到了指针,详情看深度解密Go语言之unsafe - 知乎 (zhihu.com)


按我的理解就是:

  • go语言中是有c语言中的指针的机制的,但是他为了安全,有种种限制,go语言中的一般指针是不能进行数学运算的。

下面用具体样例进行解释:

先来看个简单的指针用法,可以完全类比c

import "fmt"  
  
func main() {  
a := [5]int{1, 2, 3, 4, 5}  
p := &a[0]  
c := 3  
c++  
fmt.Println(*p)  
fmt.Println(c)  
}

输出结果为:

1
4

这里熟悉c指针的伙伴们应该都没问题,但是go的指针他不能进行运算,例如

在这里插入图片描述

可以发现这里报错了

那么我们有没有办法实现c语言中,也是我们想要的这种指针p++取到a[1]的值的效果呢?
那就得用到uintptr

package main  
  
import (  
"fmt"  
"unsafe"  
)  
  
func main() {  
a := [5]int{1, 2, 3, 4, 5}  
d := &a[0]  
fmt.Println(*(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(d)) + 8)))  
}

这里涉及到了两类指针,和我们的uintptr类型

  1. *类型:普通指针类型,用于传递对象地址,不能进行指针运算。
  2. unsafe.Pointer:通用指针类型,用于转换不同类型的指针,不能进行指针运算,不能读取内存存储的值(必须转换到某一类型的普通指针)。
  3. uintptr:用于指针运算,GC 不把 uintptr 当指针,uintptr 无法持有对象。uintptr 类型的目标会被回收。

unsafe.Pointer 是桥梁,可以让任意类型的指针实现相互转换,也可以将任意类型的指针转换为 uintptr 进行指针运算。

我们这里的操作是先把d指针从*int类型转化成了unsafe.Pointer类型,但是unsafe.Pointer类型不能进行运算,我们再转化为uintptr进行运行,我这里是人为计算出了一个int值占8个字节(go语言,一个int我是64位电脑就是8个字节,刚开始以为4个算错懵逼了一会儿,哭😥),当然我们也可以使用unsafe.Sizeof算字节,改成以下即可:

func main() {  
a := [5]int{1, 2, 3, 4, 5}  
d := &a[0]  
fmt.Println(*(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(d)) + unsafe.Sizeof(a[0]))))  
}

计算完毕之后再重新转化为unsafe.Pointer类型,然后再转为为*int类型, 再*运算取结果,这样我们就利用指针++取到了a[1]的值,当然这里是为了便于理解,用了如此丑陋的方式…

float:

在这里插入图片描述

这里需要注意的是浮点型没有float,而一定要选择float32或者float64

complex:

在这里插入图片描述

这里也要注意必须指定是complex64还是complex128
complex64 对应的是float32,是所有实部为float32,虚部为float32的集合
complex128 对应的是float64,是所有实部为float64,虚部为float64的集合

string:

在这里插入图片描述

与c++类似,可以直接相加运算

package main  
  
import "fmt"  
  
func main() {  
var s1 string = "qwq"  
var s2 string = "qaq"  
var s3 string = s1 + s2  
fmt.Println(s3)  
}

输出结果为:

qwqqaq

bool:

var flag bool = false

真为true
假为false

默认值

go 语言可以不对变量进行初始化,所有数据类型都有默认值。因此我们可以不用担心变量未初始化问题。

  • int 类型和uint类型的 0
  • float32float64 类型的 0.0
  • bool 类型的 false
  • string 类型的空字符串
  • complex类型的(0+0i)

rune类型

这里有个问题,就是go的基础类型中并没有char类型。但是go中有rune类型,这是int32的别称,可以当做是c中的char类型,使用了utf-8编码,数字和字母的编码和我们常见的ascii编码值是一样的。

package main  
  
import "fmt"  
  
func main() {  
    c := 'A'  
    c1 := 'a'  
    c2 := '0'  
    var c3 rune  
    c3 = '1'  
    fmt.Println(c, c1, c2, c3)  
}

输出结果为:

65 97 48 49

聚合类型

Go的聚合类型分为数组结构体

数组

go中的数组也与c++基本一致

数组的定义:var arrayName [size]dataType

其中,arrayName 是数组的名称,size 是数组的大小,dataType 是数组中元素的数据类型。

例如,以下定义了name为arraym, size为10, type为int的数组

var array [10]int

数组初始化

数组元素如果不进行初始化的话,默认为初始化为0

下面是两种初始化方法:

package main  
  
import "fmt"  
  
func main() {  
    // 第一种 
    var array1 = [5]int{1, 2, 3, 4, 5}  
    // 第二种
    array2 := [5]int{1, 2, 3, 4, 5}  
    fmt.Println(array1[1], array2[1])  
}

如果数组长度不确定,可以使用[...]代替数组的长度,编译器会根据元素个数自行推断数组的长度:

package main  
  
import "fmt"  
  
func main() {  
    // 第一种  
    var array1 = [...]int{1, 2, 3, 4, 5}  
    // 第二种  
    array2 := [...]int{1, 2, 3, 4, 5}  
    fmt.Println(array1[1], array2[1])  
}

如果设置了数组的长度,我们还可以通过 指定下标 来初始化元素, 没有指定的会默认初始化为0:

package main  
  
import "fmt"  
  
func main() {  
    // 第一种  
    var array1 = [5]int{0: 1, 1: 2}  
    // 第二种  
    array2 := [5]int{0: 1, 1: 2}  
    fmt.Println(array1[1], array2[4])  
}
数组的应用

与c++一致,可以按下标访问,修改元素

package main  
  
import "fmt"  
  
func main() {  
    a1 := [5]int{1, 2, 3, 4, 5}  
    fmt.Println(a1[1])  
    a1[1] = 0  
    fmt.Println(a1[1])  
}

输出结果为:

2
0
数组的遍历:

可以类似c++用下标遍历,也可以使用for-each遍历

package main  
  
import "fmt"  
  
func main() {  
  
    strs := [3]string{"qwq", "qaq", "=.="}  
    for i := 0; i < len(strs); i++ {  
        fmt.Println(strs[i])  
    }  
    for _, i := range strs {  
        fmt.Println(i)  
    }  
}

结构体

go中的结构体也与c++基本一致

结构体定义

结构体定义需要使用 type 和 struct 语句。struct 语句定义一个新的数据类型,结构体中有一个或多个成员。type 语句设定了结构体的名称。结构体的格式如下:

type struct_variable_type struct {
   member definition
   member definition
   ...
   member definition
}

例如:

type class struct {  
    members int  
    primaryTeacher string  
    major string  
    grade string  
    classNumber int  
}  
结构体赋值

可以使用结构体名.成员名 访问结构体成员赋值, 可以直接使用结构体名+{value1, value2, '''}赋值,也可以使用结构体名+{结构体成员名:value'''}赋值,没有赋值的会取默认值

例如:

package main  
  
import "fmt"  
  
type class struct {  
    members int  
    primaryTeacher string  
    major string  
    grade string  
    classNumber int  
}  
  
func main() {  
    class1 := class{35, "Feixin", "软件工程", "大二", 1}  
    fmt.Println(class1)  
    fmt.Println(class1.major)  
    var class2 class = class{major: "大数据"}  
    fmt.Println(class2.members)  
    fmt.Println(class2.major)  
    class2.members = 36  
    fmt.Println(class2.members)  
}

输出结果为:

{35 Feixin 软件工程 大二 1}
软件工程
0
大数据
36

引用类型

指针

go语言中是有c语言中的指针的机制的,但是他为了安全,有种种限制,go语言中的一般指针是不能进行数学运算的。详情看深度解密Go语言之unsafe - 知乎 (zhihu.com)

  1. *类型:普通指针类型,用于传递对象地址,不能进行指针运算。
  2. unsafe.Pointer:通用指针类型,用于转换不同类型的指针,不能进行指针运算,不能读取内存存储的值(必须转换到某一类型的普通指针)。
  3. uintptr:用于指针运算,GC 不把 uintptr 当指针,uintptr 无法持有对象。uintptr 类型的目标会被回收。

unsafe.Pointer 是桥梁,可以让任意类型的指针实现相互转换,也可以将任意类型的指针转换为 uintptr 进行指针运算。

这里只介绍普通类型指针,与c指针类似,一样的使用&取地址,使用*取内容,但是不可以进行运算操作,换言之,其实就是在java函数传参基本类型不方便的地方改成了c,但是又不想像c一样那么复杂又不安全就变成了这样。

使用起来与c语言相差不大,例如:

package main  
  
import "fmt"  
  
func main() {  
    a := 3  
    b := &a  
    *b = 2  
    fmt.Println(a)  
}

输出结果为

2

与c不同的是,数组名不代表数组第一个元素的地址

package main  
  
import "fmt"  
  
func main() {  
    array := [5]int{1, 2, 3, 4, 5}  
    b := &array  
    fmt.Println(*b)  
    c := &array[0]  
    fmt.Println(*c)  

}

输出结果为:

[1 2 3 4 5]
1

并且不能进行运算
在这里插入图片描述


Slice(切片)

Go 语言切片是对数组的抽象。Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。

感觉是不是有点像c++中的vector?😶,slice 有长度和容量的概念,也类似于c++中的size 和 capacity

切片的定义

var sliceName []sliceType其实就是[]中没有数量的数组,或者使用make函数

例如:

var slice []int  
// 使用make函数  
var slice3 = make([]int, 5, 10)  
slice4 := make([]int, 5, 10)  
// 第三个参数可省去
slice5 := make([]int, 10)

使用make函数时,参数分别为slice的数据类型、初始长度、容量,长度内的初始值默认为0,长度外容量内的值虽然有内存空间但不会被初始化,也不能使用。因为是动态数组,容量满了也可以继续增加元素,但是如果容量满了增加元素就会创建一个新的动态数组并把之前的元素全部copy其中,会耗费时间。

切片的初始化
package main  
  
import "fmt"  
  
func main() {  
    // 类似数组的方法:  
    var slice1 []int = []int{1, 2, 3}  
    slice2 := []int{1, 2, 3}  
    fmt.Println(slice1, slice2)  
    // 利用数组, 区间左闭右开
    array := [5]int{1, 2, 3, 4, 5}  
    slice3 := array[1:]  // 指定开头
    slice4 := array[:3]  // 指定结尾
    slice5 := array[1:3] // 指定区间 
    slice6 := array[:]   // 全部
    fmt.Println(slice3, slice4, slice5, slice6)  
    // 利用切片  
    slice7 := slice6[1:3]  // 上述利用数组的方法都可以,略过不表
    fmt.Println(slice7)  
}

结果为:

[1 2 3] [1 2 3]
[2 3 4 5] [1 2 3] [2 3] [1 2 3 4 5]
[2 3]
获取切片的长度和容量

可以使用len()函数和cap()函数获取切片的长度和容量

package main  
  
import "fmt"  
  
func main() {  
    slice := []int{1, 2, 3, 4, 5}  
    fmt.Printf("len = %d, cap = %d", len(slice), cap(slice))  
}

结果为:

len = 5, cap = 5
添加元素(append)

既然是动态数组那么必然少不了我们的添加元素了!还是我们熟悉的append。

append内置函数将元素附加到切片的末尾。如果它有足够的容量,则重新划分目标以容纳新元素。如果没有,将分配一个新的底层数组。Append返回更新后的切片。
语法为append(slice, elements)

package main  
  
import "fmt"  
  
func main() {  
    slice := []int{1, 2, 3, 4, 5}  
    fmt.Println(slice)  
    slice = append(slice, 2)  
    //也可以多个元素append
    //比如append(slice, 2, 3, 4)
    fmt.Println(slice)  
}

结果为:

[1 2 3 4 5]
[1 2 3 4 5 2]
切片的访问

与数组一样,可以通过下标访问

func main() {  
    slice := []int{1, 2, 3}  
    fmt.Println(slice[2])  
    // 输出3
}
切片的遍历

可以使用下标遍历,也可以使用for-each遍历

package main  
  
import "fmt"  
  
func main() {  
  
    strs := []string{"qwq", "qaq", "=.="}  
    for i := 0; i < len(strs); i++ {  
        fmt.Println(strs[i])  
    }  
    for _, i := range strs {  
        fmt.Println(i)  
    }  
}

map

与c++的map类似, 但略有不同

Map 是一种无序的键值对的集合。
Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。
Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,遍历 Map 时返回的键值对的顺序是不确定的。

在获取 Map 的值时,如果键不存在,返回该类型的零值,例如 int 类型的零值是 0,string 类型的零值是 “”

Map 是引用类型,如果将一个 Map 传递给一个函数或赋值给另一个变量,它们都指向同一个底层数据结构,因此对 Map 的修改会影响到所有引用它的变量。

map的定义
  1. 使用make函数
    make(map[keyType]valueType)
map1 := make(map[int]int)  
var map2 = make(map[int]int)
  1. 使用map关键字
    map[keyType]valueType{key1:value1, key2:value2, ...}, 这里注意行末一定要打逗号
map1 := map[string]int{  
    "qwq": 1,  
    "=.=": 2,  // 注意要打逗号
}  
var map2 = map[string]int{  
    "qaq": 1,  
    "0.0": 2,  
}
map的访问

与c++一样的是,我们可以通过map[key]获取到value值, 也可以通过key来修改value的值

package main  
  
import "fmt"  
  
func main() {  
    map1 := map[string]int{  
    "qwq": 1,  
    "qaq": 2,  
    }  
    fmt.Println(map1["qwq"])  
    map1["qwq"] = 3
    fmt.Println(map1["qwq"])
}

输出结果为:

1
3

不同的是我们可以这样操作

package main  
  
import "fmt"  
  
func main() {  
    map1 := map[string]int{  
    "qwq": 1,  
    "qaq": 2,  
    }  
    a, ok := map1["qwq"]  
    b, flag := map1["=.="]  
    fmt.Println(a, ok)  
    fmt.Println(b, flag)  
}

输出结果为:

1 true
0 false

这里第一个变量是返回的值,如果map中不存在该变量,返回的就为value类型的空值,比如这里int就返回0,第二个变量是返回map中是否存在该变量的bool值,如果存在则返回true,如果不存在则返回false

map的遍历

可以使用for-each range来遍历map

package main  
  
import "fmt"  
  
func main() {  
  
    map1 := map[int]int{  
        0: 48,  
        1: 49,  
        2: 50,  
    }  

    for key, value := range map1 {  
        fmt.Print(key, value)  
        fmt.Print(" ")  
    }  
}

结果为:

0 48 1 49 2 50
map键值对的删除

我们可以使用delete()函数来删除map中的键值对。

package main  
  
import "fmt"  
  
func main() {  
  
    map1 := map[string]int{  
        "qwq": 1,  
        "qaq": 2,  
        "=.=": 3,  
    }  
    delete(map1, "qaq")  
    for key, value := range map1 {  
        fmt.Println(key, value)  
    }  
}

结果为:

qwq 1
=.= 3

函数与结构体方法

golang中的函数允许返回多个值,并且可以为结构体定义方法,类似于java中的类的成员函数

返回单个值函数定义为

func name(参数1, 参数2...) 返回值type {

}

func name(参数1, 参数2...) (返回值1, 返回值2...) {

}

例如:

package main

import "fmt"

type class struct {
	major       string
	numbers     int
	teacherName string
}

func getTeacherName(cls class) string {
	return cls.teacherName
}

func (c class) getTeacherName2() string {
	return c.teacherName
}

func main() {
	c1 := class{"bigdata", 40, "Feixin"}
	fmt.Println(c1.getTeacherName2())
	fmt.Println(getTeacherName(c1))
}

结果为:

Feixin
Feixin

空接口 interface

1. 空接口的应用

空接口作为函数的参数

使用空接口实现可以接收任意类型的函数参数。

// 空接口作为函数参数
func show(a interface{}) {
    fmt.Printf("type:%T value:%v\n", a, a)
}

空接口作为map的值

使用空接口实现可以保存任意值的字典。

// 空接口作为map值
var studentInfo = make(map[string]interface{})
studentInfo["name"] = "李白"
studentInfo["age"] = 18
studentInfo["married"] = false
fmt.Println(studentInfo)

2. 类型断言

空接口可以存储任意类型的值,那我们如何获取其存储的具体数据呢?

接口值

一个接口的值(简称接口值)是由一个具体类型和具体类型的值两部分组成的。

这两部分分别称为接口的动态类型动态值

想要判断空接口中的值这个时候就可以使用类型断言,其语法格式:

x.(T)

其中:

  1. x:表示类型为interface{}的变量
  2. T:表示断言x可能是的类型。

该语法返回两个参数,第一个参数是x转化为T类型后的变量,第二个值是一个布尔值,若为true则表示断言成功,为false则表示断言失败。

func main() {
    var x interface{}
    x = "码神之路"
    v, ok := x.(string)
    if ok {
        fmt.Println(v)
    } else {
        fmt.Println("类型断言失败")
    }
}

上面的示例中如果要断言多次就需要写多个if判断,这个时候我们可以使用switch语句来实现:

func justifyType(x interface{}) {
    switch v := x.(type) {
    case string:
        fmt.Printf("x is a string,value is %v\n", v)
    case int:
        fmt.Printf("x is a int is %v\n", v)
    case bool:
        fmt.Printf("x is a bool is %v\n", v)
    default:
        fmt.Println("unsupport type!")
    }
}

因为空接口可以存储任意类型值的特点,所以空接口在Go语言中的使用十分广泛。

关于接口需要注意的是,只有当有两个或两个以上的具体类型必须以相同的方式进行处理时才需要定义接口。不要为了接口而写接口,那样只会增加不必要的抽象,导致不必要的运行时损耗。

更多推荐

公众号自定义mac命令行代码风格样式

一直看别人的公众号发的文章的代码排版是这样的风格:mac命令行风格样式看着很有逼格的样子,今天也尝试学习写了一下没想到成功了记录一下首先感谢一个网站:http://md.aclickall.com/一个专门让程序员写技术文章排版用的我这个样式就是基于大佬们的模版改了一些自己想要的样式网站打开是这样的:我这里用的是dar

LeetCode 847. Shortest Path Visiting All Nodes【状态压缩,BFS;动态规划,最短路】2200

本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章中,我不仅会讲解多种解题思路及其优化,还会用多种编程语言实现题解,涉及

【Python】使用 pyecharts 模块绘制动态时间线柱状图 ① ( 列表排序 | 使用 sorted 函数对容器进行排序 | 使用 list.sort 函数对列表进行排序 | 设置排序函数 )

文章目录一、列表排序1、使用sorted函数对容器进行排序2、使用list.sort函数对列表进行排序3、使用list.sort函数对列表进行排序-设置排序函数4、使用list.sort函数对列表进行排序-设置lambda匿名排序函数pyecharts画廊网站:https://gallery.pyecharts.org

健康云HIS系统源码,满足基层医疗机构业务需求,提供挂号支持、病患问诊、电子病历、开药发药、会员管理、统计查询、医生站和护士站等功能

云his系统源码二级医院HIS系统全套源代码自主研发,自主版权一款满足基层医疗机构各类业务需要的健康云HIS系统。该系统能帮助基层医疗机构完成日常各类业务,提供病患挂号支持、病患问诊、电子病历、开药发药、会员管理、统计查询、医生站和护士站等一系列常规功能,能与公卫、PACS等各类外部系统融合,实现多层机构之间的融合管理

怎样定制开发小程序微商城_流程_报价_OctShop

互联网和5G的快速发展,变化速度1天比1天快了,小程序微商城的开发也这在浪潮中得到了蓬勃发展,小程序微商城在我们的生活当中已经非常普通了,很多人通过扫描小程序微商城二维码,进入小程序微商城进行购物。随着互联网与5G的发展,很多企业或商家通过微信生态,如:微信群,朋友圈等来发展自己企业的业务。如果我们想通过朋友圈或微信群

Redis代码实践总结

一、背景:redis从安装到实践,做一些具体的记录。1.1Redis和RedisStack和RedisEnterpriseredis简介Redis是一种开源(BSD许可)内存中数据结构存储,用作数据库、缓存、消息代理和流引擎。Redis提供数据结构,例如字符串、散列、列表、集合、带范围查询的排序集、位图、超级日志、地理

别再盯着40系,这些才是目前性价比最高的显卡

有人说,当前畸形的显卡市场成了咱们升级电脑配置的最大阻碍。在小忆看来这话说得还真没啥毛病!CPU、主板、内存、硬盘、电源,哪个不是一台电脑中的重要核心硬件;它们飘了吗?没有,各个品牌在竞争中相互制约,价格呢也都维持在一个相对合理的状态。唯独显卡领域,NVIDIA独领风骚,彻底掌控定价权。RTX40系列疯狂挤牙膏价格不降

回归测试策略指南

作为一名软件测试人员,我们需要进行回归测试,以确保代码修改后软件的既有功能不会受到影响。那么如何设计和执行有效的回归测试策略呢?本文将为大家提供一些专业建议。明确回归测试的范围回归测试不可能也不需要对软件做完整测试,要识别出核心功能和关键业务场景,将回归测试的范围控制在可管理的范围内。比如在一个电商网站修改了订单模块代

实战经验分享:如何通过HTTP代理解决频繁封IP问题

在网络爬虫和数据采集等应用中,频繁遇到目标网站封锁或限制IP的情况是非常常见的。为了解决这个问题,使用HTTP代理是一种有效的方法。本文将与您分享一些实战经验,帮助您通过HTTP代理解决频繁封IP问题,确保您的数据采集工作顺利进行。一、了解频繁封IP问题频繁封IP问题是指目标网站采取措施检测并封锁过多请求来自同一IP地

Spring 篇

1、什么是Spring?Spring是一个轻量级的IOC和AOP容器框架。是为Java应用程序提供基础性服务的一套框架,目的是用于简化企业应用程序的开发,它使得开发者只需要关心业务需求。常见的配置方式有三种:基于XML的配置、基于注解的配置、基于Java的配置。主要由以下几个模块组成:SpringCore:核心类库,提

RFID技术在工业智能制造生产线中的应用

随着自动化和信息化的快速发展,工业智能制造成为制造业的重要趋势,在制造商的生产线上,准确获取和管理工艺流程等各个环节的信息至关重要,作为物联网感知层的核心组成部分,RFID技术以其非接触式、无感知的特点,实现了智能化的识别和数据采集,通过RFID电子标签实现了设备的互联,在复杂的工业制造环境中,结合RFID电子标签、R

热文推荐