栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Go语言

javer转go入门笔记-Go的声明语法思想与规则

Go语言 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

javer转go入门笔记-Go的声明语法思想与规则

摘要

本文参考了go语言官方文档,对比了C声明语法的不足,解释了go语言声明语法的特点及其规则。

1、C语言的声明语法

go语言的变量定义主要对照C语言,在C语言的基础上进行改进的。C语言中的声明语法包括变量声明和函数声明两种,其规则分别如下:

变量声明

C语言中,变量的声明主要包含两个部分,放在左边的变量类型和放置在右边的变量名称,如基本数据类型、数组、指针等三种主要类型的定义如下:

int a;
int b[];
int *c;
函数声明

函数的声明包含返回变量类型、函数名称、输入参数三个部分,其声明格式为
返回变量类型 函数名称(输入参数类型 输入参数名称){},如:

int main(int argc,char *argv[])
2、C语言的声明语法评价

C语言的声明方法是比较巧妙的,将类型放在左边直接代表声明变量,不需要增加额外的声明语法。然而,在Go语言官方文档中详细总结了很多C语言声明的问题,并提出了go语言在声明语法中改进的思路。其中,我认为C语言的声明语法其实问题并不多,其两点问题如下:

  • 1、变量名称和类型没有完全区分,如声明数组int a[]、指针数组 int *b[]等,这会导致声明语法不易阅读。并且导致理解容易混乱,同样是int类型,却可以定义整型、数组、指针等等。当前热门的java等都处理了这个问题,其变量的类型和名称是完全独立的,如数组定义写为int[] a = new int[];
  • 2、由于类型和声明语法的重用,代码中类型的解析比较困难。也会导致C、java语言中变量强制转换都会为类型加上括号等情况。
3、Go语言的声明语法 变量声明

Go语言在设计声明语法时主要考虑其易读性,符合阅读习惯,同样是第1节中的三种声明情况,在阅读可以表示为:

  • a: int
  • b: array[3] of int
  • c: pointer to int

其特点是类型在变量名之后,中间通过符号:表明在定义一个变量。Go语言对其精炼修改,并将var作为语法声明关键字,得到其声明语法规则。其基本数据类型、数组、指针等三种主要类型的定义如下:

var a int = 5
var b [3]int = []int{1,2,3}
var c *int = &a

也可以使用符号:替代var关键字,并默认进行类型推导:

a := 5
b := [3]int{1,2,3}
c := &a

可以看到Go语言的语法声明其实是比较易读的,特别是设计到复杂的一些类型,比如数组指针*[3]int,可以读作point to array[3] of int。

函数声明

Go语言的函数声明同样遵循变量声明的准则并利用func作为函数声明关键字,如:

func main(argc int, argv []string) int
4、golang函数声明规则的一个优势
  • 由于C中函数没有其类型关键字,因次函数类型和它的名称是完全耦合的,这有时是不灵活的。go语言中明确函数类型关键字为func,函数本身只是该类型的一个值,这使得函数的值传递、闭包等实现十分方便,案例如下:
//函数的值传递
hypot := func(x, y float64) float64 {
    return math.Sqrt(x*x + y*y)
}
fmt.Println(hypot(5, 12))

//函数值作为另一个函数的输入参数
func compute(fn func(float64, float64) float64) float64 {
	return fn(3, 4)
}
compute(hypot)
//闭包的实现
func adder() func(int) int {
	sum := 0
	return func(x int) int {
		sum += x
		return sum
	}
}
func main() {
	pos := adder()
	for i := 0; i < 10; i++ {
		fmt.Println(pos(i))
	}
}
****输出****
0
1
3
6
10
15
21
28
36
45
闭包概述

闭包的实现形式通常为:

  • 用户创建了一个函数func1,func1在函数体内又声明了另一个函数func2,并将func2作为值传递出去。
  • 用户声明一个函数类型的变量fn来接收返回参数化func2之后,可以将fn当作普通函数来运行。
    需要注意的是在func1中可以定义局部变量,这些局部变量对func2是可见的,在func1函数执行完成后那些被func2引用过的局部变量会被保存起来,并仅对fn可见,这就是闭包的关键点。
    如果从内存模型来解释上述案例的闭包,就是在调用adder()时局部变量sum保存在方法栈的局部变量表中,当方法执行完毕出栈时由于返回的fn函数还引用着sum变量,此时go会将sum保存到堆中进行存储,且只有fn函数能够对这两个变量的引用,其他地方是无法引用这两个变量的,这其实和Java的虚拟机模型是一致的,这就是闭包的核心所在,这种结构在go中拥有极大的威力。
go闭包能够实现的核心

在go中函数可以作为基本数据类型进行值传递并作为函数返回参数

闭包的作用

go是没有类的,因此也没有java中私有变量、公有变量这些概念。在go中,只要定义了一个非局部变量,那么他就是公有的,通过闭包可以实现私有变量这一操作,这是非常重要的。比如你写了一个工具包,内部需要有很多非局部变量,但是又不想这些变量对使用者可见,这时就可以使用闭包方便的解决。

5、Go语言变量声明测试代码 代码:
package main
import (
    "fmt"
    "unsafe"
)
// 变量定义测试
func main() {
    // 1、直接通过var关键字命名,如果未指定初值,go会为其附默认初值
    // 这和java是不同的,java的局部变量是必须附初值的,而静态变量和全局变量不需要,这和JVM处理有关系
    fmt.Println("**************************************************************************************************************")
    fmt.Println("1、直接通过var关键字命名,如果为指定初值,go会为其附默认初值")
    fmt.Println("这和java是不同的,java的局部变量是必须附初值的,而静态变量和全局变量不需要,这和JVM处理有关系")
    fmt.Println("")
    var i int = 11
    var ii int //会默认附初值
    fmt.Println("i =", i, "ii =", ii)
    fmt.Println("")
    // 2、自动类型推导
    fmt.Println("**************************************************************************************************************")
    fmt.Println("2、自动类型推导,不指定类型")
    fmt.Println("")
    var j = 11.34
    var k = "sddda"
    fmt.Println("j =", j)
    fmt.Println("k =", k)
    fmt.Println("")
    // 3、var省略 :=方式
    fmt.Println("**************************************************************************************************************")
    fmt.Println("3、省略var 通过:=方式定义并赋值")
    fmt.Println("")
    l := 3.4
    fmt.Println("l =", l)
    fmt.Println("")
    // 4、多变量命名(4种方式)
    fmt.Println("**************************************************************************************************************")
    fmt.Println("4、多变量命名(4种方式)")
    fmt.Println("①:var x1, x2, x3 int = 1, 2, 3")
    fmt.Println("②:var n1, n2, n3 = 1, 2, 3  省略类型")
    fmt.Println("③:m1, m2, m3 := 1, 2, 3  省略var")
    fmt.Println("")
    var x1, x2, x3 int = 1, 2, 3
    fmt.Println("x1 x2 x3=", x1, x2, x3)
    var n1, n2, n3 = 1, 2, 3
    fmt.Println("n1 n2 n3=", n1, n2, n3)
    m1, m2, m3 := 1, 2, 3
    fmt.Println("m1 m2 m3=", m1, m2, m3)
    var (
        l1 = 1
        l2 = 2
        l3 = 3
    )
    fmt.Println("l1 l2 l3=", l1, l2, l3)
    fmt.Println("")
    // 5、查看数据类型及其占用的字节数
    fmt.Println("**************************************************************************************************************")
    fmt.Println("5、查看数据类型及其占用的字节数")
    fmt.Println("通过Printf+\T方式输出类型,unsafe.Sizeof输入字节大小")
    fmt.Println("")
    q := -1.0
    fmt.Printf("q为%v,的类型是%T,占用%d个字节n", q, q, unsafe.Sizeof(q))
    fmt.Println("")
}
输出

1、直接通过var关键字命名,如果为指定初值,go会为其附默认初值
这和java是不同的,java的局部变量是必须附初值的,而静态变量和全局变量不需要,这和JVM处理有关系
i = 11 ii = 0


2、自动类型推导,不指定类型
j = 11.34 k = sddda


3、省略var 通过:=方式定义并赋值
l = 3.4


4、多变量命名(4种方式)
①:var x1, x2, x3 int = 1, 2, 3
②:var n1, n2, n3 = 1, 2, 3 省略类型
③:m1, m2, m3 := 1, 2, 3 省略var

x1 x2 x3= 1 2 3
n1 n2 n3= 1 2 3
m1 m2 m3= 1 2 3
l1 l2 l3= 1 2 3


5、查看数据类型及其占用的字节数
通过Printf+T方式输出类型,unsafe.Sizeof输入字节大小
q为-1,的类型是float64,占用8个字节

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/904051.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号