【Go】初识Go语言

初识Go语言

本篇内容的基础学习参考自菜鸟教程Go语言

一、了解Go语言的结构

Go程序结构
上图是一个简单的结构

go的代码按每行结束,可以不加分号结束。但是在单行内写多行就要自己添加分号分割内容

(一)包名

package main

首先,一个Go文件需要一个包名,包名可以为main,表示一个可独立执行的程序。可以运行的Go程序都包含一个名为main的包。

没有声明包名将会报错~
在这里插入图片描述
(二)导入包

import "fmt"

or

import (

	"fmt"

)

然后,如果需要使用一些内置函数,则需要导入相应的包,导入的方式为

import “包名”

Go语言导入的包必须要被使用,导入包却没有使用将报错~
在这里插入图片描述
(三)main函数

func main(){
    fmt.Println("")
}

学习过C或Java的朋友应该都知道main函数,Go的main函数也类似。Go程序开始时就会执行main函数,没有main函数将报错,如下图~

在这里插入图片描述

二、变量和常量

(一)Go的变量声明

var [paramName] [paramType]

//未声明的变量自动赋予缺省值
var myVal int
var myVal2 int = 1

go还有一种快捷的声明方式

[paramName] := [paramVal]

myVal := "第一个Go变量"

这个声明方式等效于

var myVal string
myVal = "第一个Go变量"

太好了,编辑器自动判断了myVal的值!

但是,不能在这种声明方式前声明。不然,就会报错~

在这里插入图片描述

一个一个值赋值麻烦?go可以多个值一起赋!

var _a string
var _b , _c int 
_a , _b , _c = "初值" , 2 , 1

or

a , b , c := 1 , 2 , "初值"

(二)变量的交换

go的变量交换有一种极简的写法

a , b = b , a

(三)常量的声明

const [paramName] [paramType]

const MYCONST int = 1

const MYCONST2 = "第二个go常量"

const (
	MYCONST3 = 0
    MYCONST4 = 1
)

Go还有一个特别有意思的东西,叫iota

iota在const内出现的第一次会被重置为0,在新的一行被使用时会自加1。

那么在这里定义

const (
	A = iota
    B
	C = "No iota"
	D
	E = iota
)
fmt.Println(A,B,C,D,E)

试问ABCDE分别是什么值?
在这里插入图片描述
这代表即使没有使用iota,也会加1。

那么,如果将多行常量声明在一行呢?

const (
	A = iota;B;C = "No iota"
	D
	E = iota
)
fmt.Println(A,B,C,D,E)

在这里插入图片描述
结果没变~所以正确来说iota并不是一行加1,而是遇到下一个常量加1!

三、Go函数

终于到函数了!先奉上go的函数结构

(一)函数结构

func [funcName] ([paramsName] [paramsType]) [returnParamsType]{

​ …

}

func Add(a , b int) int {
    return a + b
}

func Swap(a , b int) (int , int) {
    return b , a
}

从上面的例子可以注意到,go函数可以返回 多 个 值!(落泪)

为什么a没有指定类型?那如果上面的例子给a赋一个string的值会怎么样嘞?

func Swap(a , b int) (int , int) {
	a = "123"
    return b , a
}

在这里插入图片描述

试一下只给a指定类型

func Swap(a int, b) (int , int) {
    return b , a
}

在这里插入图片描述
(如果传入值的类型一样,那么可以只在后面的参数声明类型)

(二)参数传递方式

go参数传递有常规的 值传递 和 引用传递

  1. 值传递

    func main(){
    	a , b := 1 , 2
    	Swap(a , b)
    	fmt.Println(a , b)
    }
    
    func Swap(a , b int){
    	a , b = b , a
    }
    

在这里插入图片描述
可以看到main函数中a、b的值并没有改变

  1. 引用传递

    func main(){
    	a , b := 1 , 2
    	Swap(&a , &b)
    	fmt.Println(a , b)
    }
    
    func Swap(a , b *int){
    	*a , *b = *b , *a
    }
    

在这里插入图片描述
a、b值交换

&a表示a的指针,也可以理解为a的地址,计算机内a变量的门牌号,类型是[*a的类型],这里是*int。引用传递的swap函数相当于交换了a、b的地址,a住在了b的家,b去了a的家里面。

(三)函数变量作为参数

在go中,函数也能作为变量。类型是 func([paramsType])([returnParamsType])

func(int,int) (int,int)

下面的例子是callBack函数作为变量,playerAction函数调用作为变量的callBack函数

func main(){
	playAction(1,callBack)
}

func playAction(a int,f func(int)){
	f(a)
}

func callBack(x int){
	fmt.Printf("回调:%d",x)
}

(四)闭包

闭包的另一个说法就是函数返回值是匿名函数。上结构

func [funcName] () func() [returnFuncReturnType]{

​ return func() [returnType]{

​ return …

​ }

}

func GetScore() func() int{
	i := 0
	return func() int{
		i++
		return i
	}
}
func main(){
	score1 := GetScore()
	fmt.Println(score1())
	fmt.Println(score1())
	fmt.Println(score1())
}

运行结果:

在这里插入图片描述

可以看出第一次score1赋值时并没有调用函数。如果我新加入一个score2呢?

func GetScore() func() int{
	i := 0
	return func() int{
		i++
		return i
	}
}
func main(){	

	score1 := GetScore()
	fmt.Println(score1())
	fmt.Println(score1())
	fmt.Println(score1())	

	score2 := GetScore()
	fmt.Println(score2())
	fmt.Println(score2())
    fmt.Println(score2())
}

运行结果:

在这里插入图片描述

看来,每获得一个新的闭包,闭包中的i不会互相影响。

但是,把score2的赋值换一下,换成了

score2 := score1

在这里插入图片描述

运行一下,发现i继续自增。score2住进了score1的家,所以score1和score2的i都是一样的。

(五)结构体方法

结构体struct可以包含很多变量,结构体方法可以省略一些繁杂的过程。

上结构:

func ([structName] [structType]) [funcName] () [returnParamsType]{

}

如果使用普通的方法对结构体进行操作,比较复杂:

 type Circle struct{
	radius float64
}

func main(){
	var c1 Circle
	c1.radius = 10
	fmt.Println(GetArea(c1.radius))
}

func GetArea(r float64) float64{
	return r * r
}

这种方法每次需要自己传入参数。结构体方法是不需要的:

type Circle struct{
	radius float64
}

func main(){
	var c1 Circle
	c1.radius = 10
	fmt.Println(c1.GetArea())
}
//结构体方法
func (c Circle)GetArea() float64{
	return c.radius * c.radius
}

但需要注意的是,结构体方法只能接受一个值或指针。若有多个参数嘛……

func (c Circle,int i)GetArea() float64{
	return c.radius * c.radius
}

在这里插入图片描述

三、函数调用

(一)调用同一包(文件夹)下的函数

Go语言的同一包(文件夹)下的Go程序需要同一包名,否则报错

在这里插入图片描述

first.go:

package main

import (
	"fmt"
)

func main(){
	fmt.Println("Hello World!");
	fmt.Println(Add(1,2));
}

alg.go:

package alg

func Add(a ,b int) int {
	return a + b
}

这里将alg.go的包名改为main,再在cmd命令行中build一下,成功。

在这里插入图片描述

(二)调用不同包函数

遇到报错cannot find module for path的话,先尝试cmd输入

go env -w GO111MODULE=off

C:\Go_WorkSpace\firstGo\first.go:

package main

import (
	"fmt"
	"./Alg"
)

func main(){
	fmt.Println("Hello World!");
	fmt.Println(myClass.Add(1,2));
}

在使用到其他包函数或变量的程序中导入对应包(文件夹名),调用时在函数前加上包名

C:\Go_WorkSpace\firstGo\Alg\alg.go:

package myClass

func Add(a ,b int) int {
	return a + b
}

好了,下次再学

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值