Go基本语法

1. 变量声明
  • var name type 指定变量类型,若不赋值为默认值
  • var name = value(推断体:根据值类型隐式表明变量类型)
  • name := value(包内变量不可用,用var声明会编译报错)
  • var (name1 = value1 name2 = value2)(聚合定义变量,多个变量之间需换行,多用于全局变量)
package main

import (
	"fmt"
)
func typeDefaultValue(){
	// 变量定义1: var name type
    var a int 	//0
    var s string	//""
    var b bool	//false
    // 0  false
    fmt.Println(a, s, b)
}

func variableDeclaration2(){
	// 变量定义2:类型推断(根据值推断变量类型)--> var name = value
    var b = 3
    var c = true
    var d, e, f = 4, "aa", false;
    // 结果:3 true 4 aa false
    fmt.Println(b, c, d, e, f)
}

func variableDeclaration3(){
	// 变量定义3:不需要var声明,仅用于函数内变量,不能用于聚合变量: name := value
    s1 := "hello go"
    // 结果:hello go
    fmt.Println(s1)
}

// 变量定义4:变量聚合定义: var(name1 = value1 name2=value2)
var (
	str = "hello go world"
	bb = true
	
	//下面语句报错:syntax error: unexpected :=, expecting type
	//cc := 33 
)

func main(){
    typeDefaultValue()
    variableDeclaration2()
    variableDeclaration3()
    //hello go world true
    fmt.Println(str,bb)
    //下面语句报错:聚合定义变量多个变量之间要换行
    //var (dd="dd" ee=44)
}
2. 值类型和引用类型

值类型

  1. 值类型的变量直接指向内存中的值。
  2. 当使用=将一个值变量赋值给另一个变量,其实是将内存中的值进行了拷贝,并不是相同的内存区域。(i和j的内存地址不同)
  3. 值类型变量的值存在栈中。
  4. 通过&b来获取b的内存地址。
package main
import (
	"fmt"
)
func main(){
	//i的内存地址:0xc0420080a8
	//j的内存地址:0xc0420080f0
	//i重新赋值后的内存地址不变:0xc0420080a8
	var i = 7
	fmt.Println(i)
	fmt.Println(&i)
	var j = i
	fmt.Println(j)
	fmt.Println(&j)
	i = 8
	fmt.Println(i)
	fmt.Println(&i)
}

引用类型
一个引用类型的变量 r1 存储的是 r1 的值所在的内存地址(数字),或内存地址中第一个字所在的位置。
这个内存地址为称之为指针,这个指针实际上也被存在另外的某一个字中。
同一个引用类型的指针指向的多个字可以是在连续的内存地址中(内存布局是连续的),这也是计算效率最高的一种存储形式;也可以将这些字分散存放在内存中,每个字都指示了下一个字所在的内存地址。

当使用赋值语句 r2 = r1 时,只有引用(地址)被复制。
如果 r1 的值被改变了,那么这个值的所有引用都会指向被修改后的内容,在这个例子中,r2 也会受到影响。

3. 常量
  • 类型只有:字符串,数字(整数,浮点,复数),布尔
  • const identifier [type] = value(type可选,编译器可以通过值推断出来)
  • 常量还可以是内置函数的值。
  • iota:特殊常量,可以被编译器修改,表示常量每加一行,它的值加1,相当于常量的行索引。
package main

import (
	"fmt"
	"unsafe"
)

const (
	d = "test"
	b = unsafe.Sizeof(d)
	c = len(d)//内置函数
)

func main(){
	//test 16 4
	fmt.Println(d, b, c)
	const (
		gg = iota	//常量中每加一行加1,初始值为0
		hh
		kk
		ll = "aaaa"
		mm			//不初始化时,默认是上一个变量的值
		nn = 100
		oo
		pp = iota
		qq
	)
	//0 1 2 aaaa aaaa 100 100 7 8
	fmt.Println(gg, hh, kk, ll, mm, nn, oo, pp, qq)
}
4. 运算符
4.1 算术运算符

+、- 、* 、/ 、%、++ 、–(加减乘除求余自增自减)

4.2 关系运算符

== 、!=、 >、 <、 >=、 <=

4.3 逻辑运算符

&&、 ||、 !

4.4 位运算符

&(全1是1)、 |(有1是1)、 ^(异或,相同为1)、 << 、>>

4.5 赋值运算符

=、 +=、 -=、 *=、 /=、 %=、 <<= 、>>=、 &= 、|= 、^=

4.6 其他运算符

&a:获取变量a的实际地址(内存地址)
*a:指针变量

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

5. 条件判断语句
package main

import (
	"fmt"
)

func main(){
	var a = 25
	// if条件语句
	if a < 20 {
		fmt.Println("a < 20")
	} else {
		fmt.Println("a 不小于 20")
	}
	fmt.Printf("a的值为: %d\n", a)
	
	//switch语句
	var score = 90
	var level = "F"
	switch {
		case score >= 90 : level = "A"
		case score >=80 && score <90 : level = "B"
		case score >=70 && score < 80: level = "C"
	}
	switch level {
		case "A" : fmt.Println("优秀")
		case "B" : fmt.Println("良好")
		case "C": fmt.Println("一般")
		default : fmt.Println("不及格")
	}
}
6. 循环
package main

import "fmt"

func main() {

   var b int = 15
   var a int

   numbers := [6]int{1, 2, 3, 5} 
   /* 循环 */
   LOOP: for a < 20 {
      if a == 15 {
         /* 跳过迭代 */
         a = a + 1
         goto LOOP
      }
      fmt.Printf("a的值为 : %d\n", a)
      a++     
   }  
   /* for 循环 */
   for a := 0; a < 10; a++ {
	  if a == 5 {
	      continue;
      }
      fmt.Printf("a 的值为: %d\n", a)
      if a > 8 {
	      break;
      }
   }
   for a < b {
      a++
      fmt.Printf("=a 的值为: %d\n", a)
   }
   // range 格式可以对 slice、map、数组、字符串等进行迭代循环
   for i,x:= range numbers {
      fmt.Printf("第 %d 位 x 的值 = %d\n", i,x)
   }   
}
7. 函数

func func_name([params])[returns] {
}

值传递:
调用函数的时候实际参数复制一份传递到函数中,这样在函数中对参数进行修改,并不会影响实际参数的值。
引用传递:
调用函数时将实际参数的地址传递到函数中,函数对参数的修改将影响到实际参数的值。

package main

import "fmt"

func exchange1(x,y int) int {
	var temp int;
	temp = x;
	x = y;
	y = temp;
	return temp;
}

func exchange2(x *int,y *int) int {
	var temp int;
	temp = *x;
	*x = *y;
	*y = temp;
	return temp;
}

func main() {
	var a = 100;
	var b = 200;
	
	fmt.Printf("交换前a的值: %d\n", a)
	fmt.Printf("交换前b的值: %d\n", b)
	exchange1(a, b)
	fmt.Printf("值传递交换前a的值: %d\n", a)
	fmt.Printf("值传递交换前b的值: %d\n", b)
	exchange2(&a, &b)
	fmt.Printf("引用传递交换前a的值: %d\n", a)
	fmt.Printf("引用传递交换前b的值: %d\n", b)
}

函数用法:作为值,作为闭包,作为方法
Go中的方法类似于java中类的成员方法

package main
import (
	"fmt"
	"math"
)

/* 函数作为返回值
	匿名函数作为闭包,在闭包中对i递增1*/
func getSqueue() func() int{
	i := 0
	return func() int{
		i += 1
		return i
	}
}

func main() {
	/* 声明函数变量
		函数作为值
	*/
	getSquareRoot := func(x float64) float64 {
		return math.Sqrt(x)
	}
	/* 使用函数 :结果3*/
	fmt.Println(getSquareRoot(9))
	
	getNextNumber := getSqueue()
	fmt.Println(getNextNumber())
	fmt.Println(getNextNumber())
	fmt.Println(getNextNumber())
}
8. 变量作用域
  • 局部变量:函数体中的变量,作用域在函数内
  • 全局变量: 函数体外的变量,全包或包外(导出后)
  • 形式参数:函数定义中参数,作为函数的局部变量来使用。

全局变量和局部变量可以同名,函数内优先使用局部变量

9. 数组

数组是具有相同唯一类型的一组已编号且长度固定的数据项序列:类型相同,长度固定。

声明方法:

package main
import "fmt"
func main() {
	//长度为3类型为String的数组arr
    var arr [3] string
    fmt.Println(len(arr)) // 3
    //定义数组同时初始化
    var arr1 = [3] string {"hello", "","go"}
    for i:=0;i<len(arr1);i++ {
	    fmt.Println(arr1[i])
    }
    //根据数组元素个数确定数组长度
    var arr2 = [...] string {"hello", "go"}
    fmt.Println(len(arr2))	//2
}
9.2 多维数组
package main
import "fmt"
func main() {
	//声明二维数组x行y列
    //var arr [x][y][...] int
    //初始化二维数组
    var arr =[3][4]int {
		{0,1,2,3},
		{1,2,3,4},
		{2,3,4,5},
    }
    fmt.Println(len(arr))
}
10. 指针

定义:var name *type

package main
import "fmt"
func main() {
	var a = 10	//声明int变量
	var ip *int	//声明指针变量
	ip = &a		//给指针变量赋值,如果没有这一步,ip的值为nil(空指针)
	var pptr **int //指向指针的指针
	pptr = &ip
	
	fmt.Printf("变量a的值:%d\n", a)	//变量a的值:10
	fmt.Printf("变量a的地址:%d\n", &a)	//变量a的地址:825741320320
	fmt.Printf("指针变量的值:%d\n", ip)	//指针变量的值:825741320320
	fmt.Printf("指针变量的地址:%d\n", &ip)	//指针变量的地址:825741443096
	fmt.Printf("通过指针获取变量的值:%d\n", *ip)	//通过指针获取变量的值:10
}
11. 结构体
  1. 类似于java中的类,是一个数据集合
  2. type class_name struct{}
  3. 访问结构体成员:结构体.成员名
  4. 结构体间赋值操作,指向的内存空间并不是同一块,和java中不一样
package main

import "fmt"

//结构体,类似于java中的类
type Book struct {
	name string
	author string
	subject string
	bid int
}

func main() {
	//初始化类方法一
	b1 := Book{"盘龙", "我吃西红柿", "小说", 10001}
	fmt.Println(b1)
	//初始化类方法二
	b2 := Book{name:"星辰变", author:"我吃西红柿", subject:"小说", bid:10002}
	fmt.Println(b2)
	//初始化类方法二
	b3 := Book{name:"吞噬星空", author:"我吃西红柿", subject:"小说"}
	fmt.Println(b3)
	//编译错误:cannot use 10001 (type int) as type string in field value
//	b4 := Book{"盘龙", "我吃西红柿", 10001}
//	fmt.Println(b4)

	var bo1 Book
	var bo2 Book
	bo1.name = "武动乾坤"
	bo1.author = "天蚕土豆"
	bo1.subject = "小说"
	bo1.bid = 20001
	bo2.name = "大主宰"
	bo2.author = "天蚕土豆"
	bo2.subject = "小说"
	bo2.bid = 20002
	fmt.Println(bo1)
	fmt.Println(bo2)
	fmt.Println(bo1.name)
	fmt.Println(bo2.bid)
	
	var ptr *Book
	ptr = &bo1
	fmt.Printf("bo1的结构体指针:%d\n", ptr)
	fmt.Printf("bo2的结构体指针:%d\n", &bo2)
	printBook(ptr)
	//这样和java是不一样的,java中这样的赋值操作指向对象是指向同一内存空间,打印出来的name是相同的,go中并不是
	var bo3 = bo1
	bo3.name = "wuuu"
	//指针访问成员:武动乾坤
	//title内存地址:825741304192
	//指针访问成员:wuuu
	//title内存地址:825741304576
	printBook(&bo1)
	printBook(&bo3)
}

func printBook(book *Book) {
	//var title = book.name
	fmt.Printf("指针访问成员:%s\n", book.name)
	fmt.Printf("title内存地址:%d\n", &book.name)
}
12.map

定义map方式:

  1. 声明map:var m1 map[key-type]value-type
  2. 初始化map: m1 = make(map[key-type]value-type)
package main

import "fmt"

func main() {
	//定义map
	var m1 map[string]int
	//初始化
	m1 = make(map[string]int)
	fmt.Println(m1)	//map[]
	//放入键值对
	m1["语文"] = 98
	m1["数学"] = 100
	m1["英语"] = 99
	m1["物理"] = 100
	//遍历
	for k := range m1 {
		fmt.Printf("我的%s成绩=%d\n", k, m1[k])
	}
	//判断是否存在,如果存在返回两个值:1.key对应value;2.bool类型的flag
	v, isExist := m1["化学"]
	if isExist {
		fmt.Printf("我的化学成绩=%d\n", v)
	} else {
		//value=%!(EXTRA int=0)
		fmt.Printf("value=", v)
		fmt.Printf("我的化学成绩还没出来\n")
	}
	//删除元素,需要两个参数,map和要删除的key
	delete(m1, "数学")
	fmt.Printf("删除====\n")
	//遍历
	for k,v := range m1 {
		fmt.Printf("==我的%s成绩=%d\n", k, v)
	}
}
13. range

range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对的 key 值。

14. slice 切片(动态数组)
package main

import "fmt"

func main() {
	//定义slice
	var s1 []string
	fmt.Println(s1)
	s2 := make([]string, 3)
	fmt.Println(s2)
	var arr = [] string {"语文", "数学", "英语", "物理", "化学", "生物", "音乐"}
	s := arr[1:3]
	for index := range s{
		fmt.Println(s[index])
	}
	
}
15. 接口
  1. 定义接口的方式:
    type name interface{
    method1() [return-type]
    method2() [return-type]
    }
  2. 结构体实现接口中的方法就是实现该接口
package main

import "fmt"
//定义Animal接口和eat()方法
type Animal interface{
	eat()
}
//定义动物:狗
type Dog struct {
}
//重写接口Animal方法
func (dog Dog) eat() {
	fmt.Println("狗狗吃骨头")
}
//定义动物:猫
type Cat struct {
}
//重写接口Animal方法
func (cat Cat) eat() {
	fmt.Println("猫猫吃老鼠")
}
func main() {
	var animal Animal = new(Dog)
	animal.eat()
	
	animal = new(Cat)
	animal.eat()
}
16.并发

Go语言支持并发,通过go关键字来开启goroutine.
goroutine是轻量级线程,它的调度是由Golang运行时进行管理的。

go function-name(params)

package main

import (
	"fmt"
	"time"
)
func say(str string){
	for i:=0; i<5; i++ {
		time.Sleep(100* time.Millisecond)
		fmt.Println(str)
	}
}
func main() {
	go say("hahaha")
	say("aaaaa")
}

go语言的线程间通过channel通道进行通信, <-用于执行通道方向,如果没有,则表示通道是双向通道。

package main

import (
	"fmt"
	"time"
)
func say(str string){
	for i:=0; i<5; i++ {
		time.Sleep(100* time.Millisecond)
		fmt.Println(str)
	}
}
func main() {
	//创建一个channel
//	ch := make(chan int)
//	var i = 1
	//ch <-i	//把i放到通道
	//v := <-ch	//接收通道中的值
	//fmt.Println(v)
	//***fatal error: all goroutines are asleep - deadlock!
	//***死锁,通道不带缓冲区时,发送方会阻塞,直到接收方接收数据
	
	ch := make(chan int, 10)
	var i = 1
	ch <-i	//把i放到通道
	v := <-ch	//接收通道中的值
	fmt.Println(v)
	//如果通道带缓冲,发送方则会阻塞直到发送的值被拷贝到缓冲区内;
	//如果缓冲区已满,则意味着需要等待直到某个接收方获取到一个值。
	//接收方在有值可以接收之前会一直阻塞。
}

如果通道接收不到数据后 ok 就为 false,这时通道就可以使用 close() 函数来关闭。
v, ok <-ch
close(ch)

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于上面的引用内容,golang的基础语法学习可以参考以下几个步骤: 1. 首先,我们需要安装golang的开发环境。你可以直接进入官网(https://go.dev/)下载并安装golang的解释器。 2. 接下来,我们可以开始学习golang的语法。从上面的引用内容可以看出,golang的语法和Java的结构很相似,所以如果你之前有Java编程的经验,可以借鉴一些类比来学习。但是即使你没有Java的经验,也不用担心,golang的语法相对简单并且易于学习。 3. 另外,golang被称为“云计算时代的开发利器”,在使用过程中给人一种优雅、亲切、舒适的感觉。因此,在学习golang的过程中,你可能会发现它的语法设计和使用方式非常人性化。 综上所述,学习golang的基础语法可以通过安装开发环境、参考Java的结构以及体验其优雅、亲切、舒适的特点来进行。希望这些信息能够帮助你开始学习golang的基础语法。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [一文看完golang基础语法](https://blog.csdn.net/qq_35889508/article/details/128125279)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值