虽然写Go语言已经一年有余,认识Go语言已经近三年,但是写Go代码的快乐并未随着时间的推移而逐渐消沉,有时仍然会因为写一段伶俐的代码而感到很酷,所以想专门写一篇基础性的文章,来记录一下Go语言中那些很酷的语法,非常适合Go语言的新手同学哦!:laughing:
列个大纲先看下具体有哪些吧:
以下是正文:
知道Go语言是有多么简洁了吧:
func add(i int) (int, error) {
return i + 1, nil
}
func TestLessIsMore(t *testing.T) {
//声明变量i
i := 10
j, _ := add(i) //屏蔽err返回值
fmt.Println(j)
_, _ = add(i) //屏蔽全部返回值
}
匿名函数、闭包和lambda三者是完全不同的三个概念,但是又有着相互的关联。
首先是匿名函数,它是指在代码中定义的没有名字的函数。匿名函数可以被赋值给变量,也可以作为参数传递给其他函数。
闭包是指一个函数内部引用了外部函数的变量,并且可以在函数外部被调用或访问时,依然能够保持对这些变量的访问能力。换句话说,闭包是一个函数以及其引用的外部变量的组合体。
在Go语言中,闭包的实现非常简洁。当一个函数内部定义了一个匿名函数,并且这个匿名函数引用了外部函数的变量时,Go语言会自动将这些变量捕获到闭包中。通过闭包,我们可以在函数外部对这些变量进行访问、修改等操作,即使外部函数已经执行完毕,这些变量的值也会被保留。
lambda表达式是一种函数式编程的概念,它是一种匿名函数的简洁语法表示。在一些编程语言中,如Python、JavaScript等,lambda表达式可以用一种紧凑的方式定义一个匿名函数。通常情况下,lambda表达式用于编写简单的、单行的函数逻辑。
虽然匿名函数和lambda表达式有相似之处,都是指没有名称的函数,但是它们的使用场景和语法细节可能会有所不同。在Go语言中,匿名函数的定义比较灵活,可以包含多行代码,有更多的语法支持;而lambda表达式通常用于简单的、单行的函数逻辑。另外,Go语言中没有直接对应于lambda表达式的语法,但可以通过匿名函数来实现类似的功能。
匿名函数和lambda:
type operation func(int, int) int
func calculate(a, b int, op operation) int {
return op(a, b)
}
func TestFun(t *testing.T) {
//匿名函数
f := func(i, j int) int {
return j + i
}
f(1, 1)
// lambda函数示例
add := func(a, b int) int {
return a + b
}
subtract := func(a, b int) int {
return a - b
}
result1 := calculate(5, 3, add)
fmt.Println(result1) // 输出:8
result2 := calculate(5, 3, subtract)
fmt.Println(result2) // 输出:2
}
Go实现闭包:
func TestBiBao(t *testing.T) {
// 外部函数
outer := func() {
// 外部变量
count := 0
// 内部函数(闭包)
inner := func() {
count++
fmt.Println(count)
}
// 调用内部函数
inner()
}
// 调用外部函数
outer() // 输出:1
outer() // 输出:1
}
在上面的代码中,我们定义了一个外部函数outer
,它内部定义了一个匿名函数inner
。inner
引用了外部函数outer
的变量count
。每次调用outer
函数时,都会创建一个新的闭包,这个闭包包含了独立的count
变量。
在调用outer
函数时,内部函数inner
会被调用,并对count
变量进行递增操作,并输出结果。由于闭包捕获了外部变量,所以每次调用内部函数时,都能正确地访问和修改之前的count
值。
需要注意的是,在每次调用outer
函数时,都会创建一个新的闭包,因此每次调用时的count
变量都是独立的。这就是闭包的特性之一,它可以在函数调用之间保持状态。
闭包在一些场景下非常有用,例如:
需要注意的是,闭包引用的外部变量在闭包函数内部可能会被修改,因此在使用闭包时需要注意变量的生命周期和可变性。
go defer
是 Go 语言中的语句,它用于在函数返回之前执行一些代码。使用 defer
语句可以确保在函数执行完毕后,一些必要的清理工作或者收尾工作被执行。
func TestDefer(t *testing.T) {
defer func() {
fmt.Println("defer func ...")
}()
fmt.Println("no defer ...")
}
Go最厉害的特性之一,可以看下我这篇文章的详解:深入浅出Go并发之协程—goroutine
func TestGoroutine(t *testing.T) {
group := sync.WaitGroup{}
group.Add(1)
go func() {
fmt.Println("this is go Sou fun ...")
group.Done()
}()
group.Wait()
}
先看代码,这是Go语言中将日期转换为YYYY-MM-DD HH:MM:SS的函数,当时二话没说就搜了下为什么要这样写,很快就得出了答案,是因为好记:sweat_smile:,在国外一般都是把年份放在最后,所以我们吧年份挪到最后就会发现,可以使用010203040506这样的方式记下来,貌似确实很好记......
func TestTimeFormat(t *testing.T) {
//12小时制
format := time.Now().Format("2006-01-02 03:04:05")
fmt.Println(format)
//24小时制
format2 := time.Now().Format("2006-01-02 15:04:05")
fmt.Println(format2)
}
Go语言中的异常处理机制可以让我们在程序中捕获和处理错误和异常情况,而不是使用try...catch...这样的异常块来缓存异常。这样的设计可以让我们更灵活地处理错误和异常,并且可以更好地控制程序的流程。
与此同时,使用defer+recover()可以让我们捕获程序中可能发生的异常。
func TestRecover(t *testing.T) {
f := func() {
panic("has err ...")
}
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
}()
f()
}
在Go语言中,通道(channel)是一种用于在goroutine之间进行通信的特殊类型。通道提供了一种方式,可以在goroutine之间传递值,这使得并发编程变得更加简单和有效。
下面是一些使用channel的方式:
func sum(n int) int {
sum := 0
for i := 0; i < n; i++ {
sum += i
}
return sum
}
func main() {
n := 1000000
c := make(chan int)
for i := 0; i < 10; i++ {
go func() {
c <- sum(n)
}()
}
for i := 0; i < 10; i++ {
sum := <-c
fmt.Println(sum)
}
}
func main() {
c := make(chan int)
for i := 0; i < 10; i++ {
go func(i int) {
c <- i
}(i)
}
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
}
好了,以上就是我总结出的Go语言中那些很酷的语法,当然想要将这些优雅的操作进行灵活的使用并非易事,而且Go语言中也存在其他非常优秀的语法和设计模式,欢迎各位读者在评论区进行分享和讨论。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。