Go语言基础语法|疑难分析及相关补充

疑难分析

1.对于range遍历的理解

eg:

package main  
  
import "fmt"  
  
func main() {  
nums := []int{2, 3, 4}  
sum := 0  
for i, num := range nums {  
sum += num  
if num == 2 {  
fmt.Println("index:", i, "num:", num)  
}  
}  
fmt.Println(sum)
}

看到这个例子,我相信很多刚刚入门的小伙伴都会感到疑惑,为什么(for i, num := range nums)这个语句等号的左边有两个对象而右边却只有一个对象呢?其实很好理解,这里的nums是一个包含三个整数的切片,而对于每个整数又存在一个索引,故等号左边的第一个对象i表示的是nums中相应元素的索引,而等号左边的第二个对象,也就是num则是相应元素的值。

2.对于结构体方法的理解

在Go语言中,结构体方法(也称为结构体函数)是一种特殊的方法,它定义在结构体类型内部,并可以像普通方法一样被结构体的实例调用。

结构体方法的作用是提供一种方便的方式来操作和处理结构体的字段,同时也可以实现一些与结构体相关的功能。相比于使用匿名函数或闭包来实现这些功能,结构体方法更加清晰、易于维护和扩展。

eg:

type Rectangle struct {
    length, width float64
}

func (r Rectangle) area() float64 {
    return r.length * r.width
}

func main() {
    rect := Rectangle{length: 10, width: 5}
    fmt.Println(rect.area())
}

代码解析:

1.首先,这段Go语言代码定义了一个名为Rectangle的结构体,该结构体有两个字段:length和width,都是float64类型。

2.接下来定义了一个方法area(),该方法属于Rectangle结构体,并返回一个float64类型的值。这个方法计算了矩形的面积,即矩形的长度乘以宽度。

3.在main()函数中,创建了一个Rectangle类型的变量rect,并初始化了它的length和width字段。然后调用了rect的area()方法,将结果打印出来。

4.最后,这段代码实现了一个简单的矩形类及其计算面积的方法,并在main()函数中进行了测试。

3.Go语言中的nil表示什么?

在 Go 语言中,nil 是一个预定义的标识符,代表指针、通道、函数、接口、映射或切片的零值。也就是说,当一个指针、通道、函数、接口、映射或切片没有被初始化时,它们的值就是 nil

需要注意的是,nil 不是 Go 语言的关键字之一,你甚至可以自己去改变 nil 的值:var nil = errors.New("hi") 这样是完全可以编译得过的,但是最好不要这样子去做。

4.关于Go语言中错误处理的理解

Go中的错误通常显式地使用返回值来表示。可以使用error类型作为函数的最后一个返回值,通过约定将其与其他返回值相关联。而不是使用异常。这提供了一种确保错误得到处理的方法,因为调用者必须显式地检查错误。

func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, errors.New("division by zero")
    }
    return a / b, nil
}

补充:在错误处理中还通常使用到panic语句,而panic语句是Go语言中用于在程序出现严重错误时终止程序执行的一种机制。当程序遇到无法恢复的错误时,可以使用panic语句抛出一个异常,并将错误信息输出到标准错误流(stderr)中。

使用panic语句的好处是可以快速终止程序的执行,避免程序继续执行导致更多的错误和资源泄漏。同时,由于panic会立即终止程序的执行,因此可以方便地进行调试和错误处理。

需要注意的是,panic语句应该谨慎使用,只有在确实需要立即终止程序的情况下才应该使用。在正常的程序逻辑中,应该尽量避免出现不可恢复的错误,而是通过合理的错误处理机制来捕获和处理错误。

5.Go语言中的时间处理

package main  
  
import (  
"fmt"  
"time"  
)  
  
func main() {  
now := time.Now()  
fmt.Println(now)  
t := time.Date(2023, 7, 26, 1, 25, 36, 0, time.UTC)  
t2 := time.Date(2023, 7, 26, 2, 30, 36, 0, time.UTC)  
fmt.Println(t)  
fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute())  
fmt.Println(t.Format("2006-01-02 15:04:05"))  
diff := t2.Sub(t)  
fmt.Println(diff)  
fmt.Println(diff.Minutes(), diff.Seconds())  
t3, err := time.Parse("2006-01-02 15:04:05", "2023-7-6 01:25:36")  
if err != nil {  
panic(err)  
}  
fmt.Println(t3 == t)  
fmt.Println(now.Unix())  
}

代码解析:

1.首先,通过import语句导入了fmttime两个包,分别用于格式化输出和处理日期和时间。

2.在main函数中,首先获取当前时间并将其赋值给变量now,然后使用fmt.Println函数将当前时间打印到控制台。

3.接下来,创建了两个时间对象tt2,分别表示2023年7月26日1点25分36秒和2023年7月26日2点30分36秒。这里使用了time.Date函数来指定日期和时间,并将结果赋值给相应的变量。

4.使用fmt.Println函数将时间对象t打印到控制台,并使用其方法获取年、月、日、时、分的值,并分别打印出来。

5.使用t.Format("2006-01-02 15:04:05")将时间对象t按照指定的格式转换为字符串,并打印出来。

6.计算时间对象t2t之间的差值,并将结果赋值给变量diff,然后使用fmt.Println函数将差值打印到控制台。

7.使用diff.Minutes()diff.Seconds()方法分别获取差值的分钟数和秒数,并打印出来。

8.使用time.Parse函数将字符串"2023-7-6 01:25:36"解析为时间对象,并将结果赋值给变量t3,如果解析过程中出现错误,则会触发panic语句终止程序执行。

9.使用比较运算符判断时间对象t3是否等于时间对象t,并将结果打印到控制台。 

10.最后,使用now.Unix()方法获取当前时间的Unix时间戳(以秒为单位),并将其打印到控制台。

6.在Go语言中%v、%+v和%#v输出数据时的区别

在Go语言中,%v、%+v和%#v是格式化输出数据时使用的占位符,它们的区别如下:

  • %v:默认的格式化方式,会将数据转换为字符串类型并输出。如果数据结构比较复杂,输出的结果可能会很长且难以阅读。
  • %+v:格式化输出数据时,会尽可能地保留原始的数据类型信息,输出的结果类似于数据的源码形式。这种方式适合调试和日志记录等场景。
  • %#v:格式化输出数据时,会输出数据的结构体名称和字段名,以及字段值的类型和值。这种方式适合开发人员查看和理解数据结构。

eg:

package main  
  
import "fmt"  
  
type point struct {  
x, y int  
}  
  
func main() {  
s := "hello"  
n := 123  
p := point{1, 2}  
fmt.Println(s, n)  
fmt.Println(p)  
  
fmt.Printf("s=%v\n", s)    //s=hello  
fmt.Printf("n=%v\n", n)    //n=123  
fmt.Printf("p=%v\n", p)    //p={1 2}  
fmt.Printf("p=%+v\n", p)   //p={x:1 y:2}  
fmt.Printf("p=%#v\n", p)   //p=main.point{x:1,y:2)  
  
f := 3.151592653  
fmt.Println(f)  
fmt.Printf("%.2f\n", f)  
}

代码解析

1.此代码首先定义了名为Car的结构体,其中的Make和Model字段都用了JSON标签来指定了在JSON编码时对应的键名。

2.然后定义了myCar的Car类型的变量,并为其赋上具体的值。

3.接下来,使用json.Marshal函数将变量myCar编码为JSON格式的字节切片([]byte)。

4.将编码后的字节切片转换为字符串,并打印输出。

8.对于strconv包(即字符串和数字之间的相互解析)中经常用到的函数汇总

  • strconv.ParseFloat():将字符串转换为float64类型的浮点数。
  • strconv.ParseInt():将字符串转换为int64类型的整数,可以指定进制和位数。
  • strconv.ParseUint():将字符串转换为uint64类型的无符号整数,可以指定进制和位数。
  • strconv.Atoi():将字符串转换为int64类型的整数,不支持进制转换。

9.对于strings包(即对于字符串的处理)中常用到的函数汇总

1.func Contains(s, substr string) bool

  • 功能说明:这个函数主要是用来判断s中是否包含substr这个子串,如果包含返回true,否者返回false。

2.func Count(s, sep string) int

  • 功能说明:这个函数主要是用来判断s中包含了多少个sep。

3.func HasPrefix(s, prefix string) bool

  • 功能说明:该函数主要判断s串中是否含有前缀prefix,如果包含,那么返回true,否则返回false。

4.func HasSuffix(s, suffix string) bool

  • 功能说明:该函数主要判断s串中是否含有后缀suffix,如果包含,那么返回true,否则返回false。

5.func Index(s, sep string) int

  • 功能说明:该函数主要判断sep串在s串中第一次出现的位置,如果不存在返回-1。

6.func Join(a []string, sep string) string

  • 功能说明:该函数主要实现字符串slice的链接功能,把slice的每一个元素通过sep进行链接。

7.func Repeat(s string, count int) string

  • 功能说明:该函数返回一个s的重复count字数的字符串。

8.func Split(s, sep string) []string

  • 功能说明:该函数s根据sep分割,返回分割之后子字符串的slice,如果sep为空,那么每一个字符都分割。

9.func ToLower(s string) string

  • 功能说明:该函数把s字符串里面的每个单词转化为小写。

10.func ToUpper(s string) string

  • 功能说明:该函数把s字符串里面的每个字符转化为大写。

11.func Replace(s, old, new string, n int) string

  • 功能说明:该函数实现在s中把old替换为new字符串,替换次数为n,如果n小于0,那么就全部替换。

代码理解:

package main  
  
import (  
"fmt"  
"strings"  
)  
  
func main() {  
a := "hello"  
fmt.Println(strings.Contains(a, "ll")) //true  
fmt.Println(strings.Count(a, "l")) //2  
fmt.Println(strings.HasPrefix(a, "he")) //true  
fmt.Println(strings.HasSuffix(a, "llo")) //true  
fmt.Println(strings.Index(a, "ll")) //2  
fmt.Println(strings.Join([]string{"he", "llo"}, "-")) //he-llo  
fmt.Println(strings.Repeat(a, 2)) //hellohello  
fmt.Println(strings.Replace(a, "e", "E", -1)) //hEllo  
fmt.Println(strings.Split("a-b-c", "-")) //[a,b,c]  
fmt.Println(strings.ToLower(a)) //hello  
fmt.Println(strings.ToUpper(a)) //HELLO  
fmt.Println(len(a)) //5  
b := "你好"  
fmt.Println(len(b)) //6  
}

Final summary

本文主要记录了博主在学习第一节课《Go语言基础语法》时碰到的疑难以及自己对于问题的探索和理解,其中还包括了我查阅资料对课程内容的相关补充,总之,Go语言是一门非常值得入手的语言。

理由如下:

  1. 简洁而强大的语言特性:Golang以简洁性为核心设计原则之一,它通过精心选择并整合其他语言的特性,使得代码更加清晰、易读、易维护。其中包括静态类型系统、自动垃圾回收、丰富的标准库等。
  2. 并发编程的易用性:Golang在语言级别支持并发编程,通过goroutine和channel的组合,使得编写高效且可扩展的并发程序变得非常容易。Goroutine可以轻松地创建和管理并发任务,而channel则提供了一种通信机制,用于安全地在不同的goroutine之间传递数据。
  3. 内置的错误处理和不一样的异常机制:Golang采用显式的错误处理方式,通过返回error类型来表示函数执行过程中可能出现的错误。这种设计有助于开发者更好地控制程序的流程,并减少意外的异常情况。
  4. 包管理和依赖解决方案:Go模块是Golang的包管理工具,为项目提供了依赖管理和版本控制的能力。它允许开发者明确指定项目所依赖的其他模块,并确保在构建应用程序时使用正确的版本。
  5. 高效的编译和执行效率:Golang的编译器将源代码直接编译为本地机器码,而非解释或虚拟机字节码,因此具有接近原生代码的执行效率。此外,Golang在内存管理、垃圾回收和并发处理方面进行了优化,使得它在高负载和并发环境下表现出色。

总而言之,Golang以其简洁性、并发性和高效性而闻名。它致力于通过提供简单但功能强大的语言特性和工具来改善开发者的生产力和代码可靠性。这使得Golang成为了构建高性能、可伸缩和可靠的应用程序的理想选择。

如有错误的地方,请大佬指正QWQ

文章最后,给大家推荐一个很好用的ai网站:aihub.52chye.cn

你可能感兴趣的:(Go语言学习路程,golang,算法,开发语言,go,后端,go1.19)