Golang快速入门

一、Go语言基础:

1、定义包名 ,说明这个文件属于哪个包,main包表示是一个可独立执行的程序,每个Go程序都包含一个名为main的包。

package main

2、引用包,这点与Java等面向对象的语言类似,引用后可直接调用(不过不需要再次声明对象),如下说明该程序需要使用fmt包中的某些函数或者是元素,那fmt就是一个非常常用的包,实现了格式化IO的函数,比如fmt.Println输出到console。

import "fmt"

3、函数声明, main函数是每个可执行的程序必须包含的,一般来说是启动后第一个执行的函数,如果有init则例外,因为init()函数会先于main开始执行。

func main()

当标识符(常量、变量、类型、函数名、结构字段等等)以一个大写字母与开头,比如说Han1,那么这样形式的标识符的对象就可以被外部包的代码所使用(要注意客户端需要先导入其所在的包),有点类似于java中的public,反之如果是小写字母开头,那必然是对包外不可见,但是在整个包的内部是可见可用的,类似于protected。

如下是一个完整的HelloWorld 程序,注意Golang 的代码规范,{ 不要另起一行(强制要求)

package main

import "fmt"

func main() {
    fmt.Println("hello world");
}

如果要运行的话,可以通过IDE的方式,或者通过命令:

  • go run filename.go

  • 也可以生成二进制文件,每次通过./filename的方式执行。

    • go build filename.go
    • ./filename

关于包

Golang的包与java的包有一定的区别:

  • 文件名和包名没有直接关系,不一定要将文件名和包名定成同一个;
  • 文件夹名和包名也是没直接关系,并非需要一致;
  • 同一个文件夹下的文件只能有一个包名否则编译报错

二、Go语言的数据类型

  • 布尔:var b bool=true

  • 数字类型:整型int、浮点型,Go还支持复数。

  • 字符串类型:一串固定长度的字符连接起来的字符序列。

  • 派生类型:

  • Pointer

    • 数组类型
    • struct
    • Channel类型
    • 函数类型
    • 切片类型
    • interface类型
    • Map类型

go 1.9版本对于数字类型,无需定义int以及float32、float64,系统会自动识别

var isActive bool //全局变量声明
var enabled,disabled=true,false //忽略类型的声明
func test(){
    var available bool //一般声明
    valid := false //简短声明
    available = true //赋值操作
}

三、Go语言变量

Go变量的声明跟js是有点像的,需要用var,或者:= ,但是数据类型要放在变量名后。

变量声明:

  • 声明一个变量并初始化:var a="RUNOOB"

  • 声明一个变量,但没有初始化,则默认是零值

    几个零值为nil的类型:

var a *int
var a []int 
var a map[string] int
var a chan int 
var a func(string) int
var a error //此处err是个接口

根据值自动判断变量的类型:var var_name = value

省略var,采用:=的方式 v_name := value,只能提出现在函数体中,相同的代码块中,不能对相同名称的变量使用初始化声明(会提示no new variables on left side of :=),在定义变量之前使用变量varname,会得到编译错误undefined:varname,如果声明了一个局部变量但是没有在相同的代码块中使用,也会得到编译错误(会提示a declared and not used)。注意:这点与Java差别很大,Go不允许声明但不使用的局部变量。

  • 下面这种方式常用于声明全局变量,全局变量允许声明但不使用。
var(
	vname1 v_type
    vname2 v_type
)

其他注意事项

  • 简单交换两个变量的值,a,b=b,a,注意变量的类型必须是相同的!
  • 空白标识符_可用于抛弃值,比如说_ , b=5,7中,5就是被抛弃的值。 _相当是一个只写变量,得不到它的值,因为Go中必须使用被声明的变量,但有时候不需要从函数中得到返回值。
  • 并行赋值也用于当一个函数返回多个返回值的时候(和python有点类似),var,err=Func1(var1)。

附上一个关于空白标识符在函数返回值时的使用case:

package main

import "fmt"

func main(){
    _,num,str=getVal()
    fmt.Println(numb,strs)
}

func getVal()(int,int,string){
    return 1,2,"hi"
}

关于值类型和引用类型

值类型的变量的值放在栈中,int、float、bool、stirng这些基本类型都是值类型,使用这些类型额变量直接指向在内存中的值。

使用 = 将一个变量的值赋给另一个变量的时候,实际上是在内存中将 i 的值进行了拷贝。一个引用类型的变量存储的是这个变量的值所在的内存地址,或者内存地址中第一个字所在的位置,内存地址称之为指针。如果是对引用类型用 = 进行赋值,那么只有引用地址被复制,如两个引用类型,r2 = r1,如果r1的值修改了,那么r2也会受影响。

关于字符串类型

a ="hello"
unsafe.Sizeof(a)

输出结果是16,字符串类型在go中是个结构,包含指向底层数组的指针和长度,二者各是8个字节,所以一共是16。

四、Go语言的常量

常量的定义格式:

const indetifier [type] = value 

如:

const b string = "hello"
const b "hello"
const c_name1,c_name2 = val1,val2

常量枚举:

const(
	Unknown = 0
    Female =1
    Male =2
)

iota: 一个可以被编译器修改的常量。

const (
	a=iota
    b
    c
)

第一个iota等于0,每当iota在新的一行被使用的时候,值自动+1,所以b=2,c=3。

package main

import "fmt"

func main(){
    const(
    	a = iota 
        b
        c
        d ="ha"
        e
        f = 100
        g
        h =iota
        i
    )
    fmt.Println(a,b,c,d,e,f,g,h,i)
}

通过运行结果可以看出来:在定义常量组时,如果不提供初始值,则表示将使用上行的表达式。

运行结果:

0 1 2 ha ha 100 100 7 8

iota 只是在同一个 const 常量组内递增,每当有新的 const 关键字时,iota 计数会重新开始。

五、Go语言运算符

内置的运算符有:算数运算符、关系运算符、逻辑运算符、位运算符、赋值运算符、其他运算符。

说下其他运算符:&a给出变量的实际地址,*a表示指针变量。

var a int = 4
var ptr *int

ptr = &a 
fmt.Println("%d",a)
fmt.Println("%d",*ptr)

打印出来的值都是4。

另外,Go的自增自减只能作为表达式来使用,不能用于赋值语句。

a = a++ //在定义常量组时,如果不提供初始值,则表示将使用上行的表达式。

六、Go语言条件、循环语句

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

  • if
  • if…else
  • if嵌套
  • switch语句
  • select语句

for循环:

for init; condition; post { }
for ; condition; {}
for{}
//for-each range 
strings := []string{"google", "runoob"}
for i, s := range strings {
    fmt.Println(i, s)
}


numbers := [6]int{1, 2, 3, 5}
for i,x:= range numbers {
    fmt.Printf("第 %d 位 x 的值 = %d\n", i,x)
}  

  • 循环控制语句:break、continue、goto

七、Go语言中的函数

一个方法就是包含了接受者的函数,接收者可以是命名类型或者结构体类型的一个值或者是一个指针,所有给定类型的方法属于该类型的方法集。

func (variable_name variable_data_type) function_name() [return_type]{
    
}

Case:

package main

import "fmt"

type Circle struct{
    redius float64
}

func main(){
    var c Circle
    c.radius=10
    fmt.Println(c.getArea())
    c.changeRadius(20)
    fmt.Println(c.radius)
    change(&c, 30)
    fmt.Println(c.radius)
}

func (c Circle)getArea() float64{
    return 3.14*c.radius*c.radius
}
// 注意如果想要更改成功c的值,这里需要传指针
func (c *Circle) changeRadius(radius float64)  {
   c.radius = radius
}
// 引用类型要想改变值需要传指针
func change(c *Circle, radius float64)  {
   c.radius = radius
}

闭包:

package main
import "fmt"
func main() {
    add_func := add(1,2)
    fmt.Println(add_func(1,1))
    fmt.Println(add_func(0,0))
    fmt.Println(add_func(2,2))
} 
// 闭包使用方法
func add(x1, x2 int) func(x3 int,x4 int)(int,int,int)  {
    i := 0
    return func(x3 int,x4 int) (int,int,int){ 
       i++
       return i,x1+x2,x3+x4
    }
}	

八、Go语言数组

声明数组

var variable_name [SIZE] variable_type
//举例说明
var blance [10] float32

初始化数组

var balance=[5]float32{1000.0,2.0,3.4,7.0,50.0}
var balance=[...]float32{1000.2,5.6}

访问数组元素

var salary float32=balance[9]

以上实例读取了数组balance的第10个元素的值。

多维数组

var threedo, [5][10][4] int

二维数组的定义方式:

var arrayName [x][y] variable_type

初始化二维数组

//Ex1
a=[3][4] int{
    {0,1,2,3},
    {4,5,6,7},
    {8,9,10,11},
}
//Ex2
b=[2][1] int{
    {1,2},{3,4}}

访问二维数组

value :=a[2][3]
var val int = a[2][3]

向函数传递数组

通过形参设定数组大小和形参未设定数组大小两种方式来声明函数。

void func1(param [10]int)
void func2(param []int)

与Java不同的是,Go的数组作为函数参数传递的是副本,函数内修改数组并不改变原来的数组。

package main
import "fmt"
func change(nums[3] int){
   nums[0]=100
}
func main() {
    var nums=[3]int{1,2,3}   
    change(nums)   //nums并未被改变   
    fmt.Println(nums[0])   
    return
}

Go的数组是值,长度是其类型的一部分,值传递;Go对数组的处理采用切片的方式,切片包含对底层数组内容的引用,作为函数参数的时候,类似于指针传递

定义了长度的数组只能传递给限制了相同数组长度的函数,没定义长度的只能传递给不限制数组长度的函数。

b:=[]int{1,2,3,4}
func boo(b []int){
    b[0],b[len(b)-1]=b[len(b)-1],b[0]
}
boo(p)
fmt.Println(p) //[4 2 3 1]

p:=[3]int{5,6,7}
func poo(p [3]int){
    p[0],p[len(p)-1]=p[len(p)-1],p[0]
}
poo(p)
fmt.Println(p) //[5,6,7]

十一、Go语言指针

一个指针变量指向了一个值的内存地址,在使用指针之前需要声明指针:

var var_name *var-type

例如:

var ip *int
var fp *float32

使用指针

package main

import "fmt"


func main(){
    
    var a int = 20
    var ip *int
    
    ip=&a
    
    fmt.Println("a的变量地址是:%x\n",&a)
    
    fmt.Println("ip变量存储的指针地址是:%x\n",ip)
    
    fmt.Println("ip变量的值是:%d\n",*ip)
    
}

空指针

一个指针被定义后没有分配到任何变量的时候,值为nil,就是空指针,和其他语言的null、NULL是一样的。

十二、Go语言结构体

数组是存储同一类型的数据,但在结构体中可以为不同项定义不同的数据类型。结构体的格式如下:

type struct_variable_type struct{
    member defination
    member defination
    ... ...
    member defination
}

一旦定义结构体类型,只能用于变量的声明,语法格式如下:

variable_name := structure_variable_type{val1,val2...valn}
variable_name := structure_variable_type{key:val1,key2:val2...,keyn:valn}

访问结构体成员

结构体.成员名。

结构体作为函数参数

package main

import "fmt"

type Books struct {
   title string
   author string
   subject string
   book_id int
}

func main() {
   var Book1 Books        /* 声明 Book1 为 Books 类型 */
   var Book2 Books        /* 声明 Book2 为 Books 类型 */

   /* book 1 描述 */
   Book1.title = "Go 语言"
   Book1.author = "www.runoob.com"
   Book1.subject = "Go 语言教程"
   Book1.book_id = 6495407

   /* book 2 描述 */
   Book2.title = "Java 教程"
   Book2.author = "www.runoob.com"
   Book2.subject = "Java 语言教程"
   Book2.book_id = 6495700

   /* 打印 Book1 信息 */
   printBook(Book1)

   /* 打印 Book2 信息 */
   printBook(Book2)
}

func printBook( book Books ) {
   fmt.Printf( "Book title : %s\n", book.title)
   fmt.Printf( "Book author : %s\n", book.author)
   fmt.Printf( "Book subject : %s\n", book.subject)
   fmt.Printf( "Book book_id : %d\n", book.book_id)
}

output:

Book title : Go 语言
Book author : www.runoob.com
Book subject : Go 语言教程
Book book_id : 6495407
Book title : Java 教程
Book author : www.runoob.com
Book subject : Java 语言教程
Book book_id : 6495700

结构体指针

结构体是作为参数的值传递,如果想在函数中改变结构体的数据内容,需要传入指针。

package main
import "fmt"

type Books struct{
    title string
    author string
    subject string
    book_id int
}

func main(){
    var Book1 Books
    var Book2 Books
    
   /* book 1 描述 */
   Book1.title = "Go 语言"
   Book1.author = "www.runoob.com"
   Book1.subject = "Go 语言教程"
   Book1.book_id = 6495407

   /* book 2 描述 */
   Book2.title = "Python 教程"
   Book2.author = "www.runoob.com"
   Book2.subject = "Python 语言教程"
   Book2.book_id = 6495700
    
     /* 打印 Book1 信息 */
   printBook(&Book1)

   /* 打印 Book2 信息 */
   printBook(&Book2)
}

func printBook( book *Books ) {
   fmt.Printf( "Book title : %s\n", book.title)
   fmt.Printf( "Book author : %s\n", book.author)
   fmt.Printf( "Book subject : %s\n", book.subject)
   fmt.Printf( "Book book_id : %d\n", book.book_id)
}

struct 类似于 java 中的类,可以在 struct 中定义成员变量。

type Rect struct{   //定义矩形类
    x,y float64       //类型只包含属性,并没有方法
    width,height float64
}
func (r *Rect) Area() float64{    //为Rect类型绑定Area的方法,*Rect为指针引用可以修改传入参数的值
    return r.width*r.height         //方法归属于类型,不归属于具体的对象,声明该类型的对象即可调用该类型的方法
}

十三、Go语言切片

切片是对数组的抽象,Go数组的长度不可改变,在特定场景中就不太灵活,所以提供了内置类型切片,可以理解为是动态数组,长度不固定,可以追加元素,再追加的时候可能使切片的容量增大。

定义切片

var identifier []type
slice := make([]type,len)
//len是数组的长度并且也是切片的初始长度,cap是指定容量
var slice1 []type=make([]type,len[capacity])

切片初始化

//直接初始化切片
s:=[]int {1,2,3}
//初始化切片,是数组arr的引用
s:=arr[:]
//将arr从下标startIndex到endIndex-1 下的元素创建为一个新的切片
s:=arr[startIndex:endIndex]
//类似的有
s := arr[:endIndex] 
s := arr[startIndex:] 
//通过切片s初始化切片s1
s1 := s[startIndex:endIndex] 

len()和cap()函数
切片是可索引的,并且可以由 len() 方法获取长度。切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少。切片是可索引的,并且可以由 len() 方法获取长度。切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少。

切片截取
可以通过设置下限及上限来设置截取切片 [lower-bound:upper-bound]

append()和copy()函数如果想增加切片的容量,我们必须创建一个新的更大的切片并把原分片的内容都拷贝过来。

package main

import "fmt"

func main() {
   var numbers []int
   printSlice(numbers)

   /* 允许追加空切片 */
   numbers = append(numbers, 0)
   printSlice(numbers)

   /* 向切片添加一个元素 */
   numbers = append(numbers, 1)
   printSlice(numbers)

   /* 同时添加多个元素 */
   numbers = append(numbers, 2,3,4)
   printSlice(numbers)

   /* 创建切片 numbers1 是之前切片的两倍容量*/
   numbers1 := make([]int, len(numbers), (cap(numbers))*2)

   /* 拷贝 numbers 的内容到 numbers1 */
   copy(numbers1,numbers)
   printSlice(numbers1)  
}

func printSlice(x []int){
   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}

Output:

len=0 cap=0 slice=[]
len=1 cap=1 slice=[0]
len=2 cap=2 slice=[0 1]
len=5 cap=6 slice=[0 1 2 3 4]
len=5 cap=12 slice=[0 1 2 3 4]

当append(list, [params]),先判断 list 的 cap 长度是否大于等于 len(list) + len([params]),如果大于那么 cap 不变,否则 cap = 2 * max{cap(list), cap[params]},所以当 append(numbers, 2, 3, 4) cap 从 2 变成 6。

十四、range关键字

range关键字用于for循环中迭代数组、切片、通道或集合的元素。在数组和切片中他返回元素的索引和索引对应的值,在集合中返回key-val对。

package main

import "fmt"

func main(){
   
    nums :=[]int{1,2,3}
    sum := 0
    //range返回切片的索引和索引对应的值,如果不需要索引通过_消除掉索引就好了,即第一个返回值为索引,第二个为索引对应的值
    for _,num:=range nums{
        sum+=num
    }
    
    fmt.Println("sum:",sum)
    
    kvs := map[string]string{"a":"apple","b":"banana"}
    for k,v := range kvs {
        fmt.Println("%s -> %s",k,v)
    }
}

range还可以用来枚举Unicode字符串,第一个参数是字符的索引, 第二个是字符本身。

for i,c := range "go"{
    fmt.Println(i,c)
}
/*
0 103
1 111
*/

获取参数列表:

package main

import(
	"fmt"
    "os"
)

func main(){
    fmt.Println(len(os.Args))
    for _,arg:=range os.Args{
        fmt.Println(arg)
    }
}

十五、Go语言Map

定义Map

两种方式,可以使用内建函数make也可以使用map关键字来定义Map。

//声明变量,不初始化默认map是nil,nil mao是不能存放键值对的
var map_variable map[key_data_type]value_data_type
//使用make函数
map_variable := make(map[key_data_type]value_data_type)

case:

package main

import "fmt"

func main(){
    
    map_country := make(map[string]string)
    
    map_country["China"]="北京"
    map_country["Japan"]="东京"
    map_country["India"]="新德里"
    
    for country:= range map_country{
        fmt.Println(country,"首都是",map_country[country])
    }
    
    capital,ok=map_country["Italy"]
    if(ok){
        fmt.Println("Italy的首都是:",captital)
    }else{
        fmt.Println("Italy的首都不存在")
    }
}

delete()函数

该函数用于删除集合的元素,参数为map和其对应的key。

delete(map_variable,key_data_variable)

十六、Go语言接口

Go提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。

type interface_name interface(
	method_name1 [return_type]
    method_name2 [return_type]
    ... ...
    method_namen [return_type]
)

/*定义结构体*/
type struct_name struct{
    /*variables*/
}

/*实现接口方法*/
func (struc_name_variable struct_name) method_name1()[return_type]{
    
}
...
func (struct_name_variable struct_name) method_namen()[return_type]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值