最最通俗易懂,并带小说情节的Go语言入门教程,没有之一,不接受反驳

简介: 最最通俗易懂,并带小说情节的Go语言入门教程,没有之一,不接受反驳

上午写了很多,电脑死机了,一下都没有了。作为一个老司机,真是大意了。

上次写了一篇关于程序员怎么学习的文章,感兴趣的可以点开链接看看,《寻根学习法》,昨晚睡不着的时候想,也许更名成《溯源学习法》更好听呢。

之前分享了一篇关于学习方法的文章,本来想着如果有一定的计算机基础,告诉大家应该学什么,然后接着再分享一些利用寻根学习法的编程教程。但是一个读者的留言改变了我的想法。

我们都曾经有过被一堆概念吓坏的时候,我们都曾经有过抱怨那些可恶的概念制造者的时候,直到后来我们和这些概念成了朋友,然后大骂一句,装啥装,不就是XX吗。

这个读者的留言让我觉得,有没有一种可能,不用那些高级的面向对象(如果不懂请忽略)的称呼,写一篇通俗易懂的编程语言入门教程?

来了,就是这篇了。

生活中很多事情都有个约定俗成的东西,比如说我们需要走门进别人家,而不是窗户。

那么对于Go 家族(嗯,为了通俗易懂,我们称为Go 家族)来说,这个大门的名字是main,小门的名字也是main。

我们写了一些 Go 的代码,可以把它理解成Go 家族的一员。那么我们去他家串门的话,他家的大门在哪呢?

他家的大门就是文件顶部有个 package main 的文件。

进了大门还要找正门, 正门是啥呢,正门就是 main 函数。

下次我们去他家逛的时候就知道了,没有大门(文件顶部有 package main 字样的) 的咱不去。进了大门,没有正门的(main 函数) 的我也不去。

你可能会问我,啥是函数?是 x = y + 1 吗?

不是。这个函数就是一段有名字的代码。

比如:

func main() {
    fmt.Println("Hello, World!")
}

其中,func 是标记,英语function的简写, main就是名称, 后面跟了一对括号。

不用去理解,记住就行了。函数就长这样。长这样的就叫函数。

碰到有些初学者,比如我,非得去思考为啥长这样就叫函数?有没有人能和我说一下,连个讲道理的人都没有吗?

后来理解了,长这样就叫函数,长那样就叫变量。没啥好问的。人家爹妈给起的名字。

既然说到变量了,变量的英文是variable,所以在Go 语言里先用 var 来说明这是变量。

其实我连变量这个名字都不想提的,担心提了你又迷糊。

既然我们把用 Go 语言写的文件拟人化成人了,那么接下来我们邀请王麻子出场了。

王麻子家的名字叫王麻子.go, 理论上应该叫go麻子更合适一些。

咱们看看王麻子家长啥样。

我们可以在电脑上找找王麻子.go, 没有的话可以创建一个。

下面我们找找他家的大门,正门。聪明如你,肯定找到了。

package main
import "fmt"
func main() {
    fmt.Println("Hello, World!")
}

其他的不认识也没关系,谁还没有第一回呢。

虽然他家还空空荡荡的,没啥东西,不过我们一起认识一下他们家族的其他成员。

和所有生完孩子的人一样,如果把我们创建的成员当成孩子的话,我们都得给他们起个名字。

龙生九种,各有不同。Go 语言也是。

人有男女,Go 语言有逻辑、数字、字符串,还有其他。具体的见了再说,一下说出来估计你也记不住。

那么Go 语言怎么起名字呢?

var 张三 string = "张三"

这里的 string就是我们说的字符串类型。需要的话可以来这里看看具体有哪数据类型。

好多其他的编程语言就这样了,也不改了。但是Go 不一样,我们还可以再简单一点。

var 张三 = "张三"

你可能会说早这样不好吗?早告诉你这样也可以,问题是他换个马甲你就不认识了,对不?

你肯定说,还有比这简单的吗?那个 var 啥的看着别扭。

如果你认识 Go 语言的设计者,你肯定想着人肯定你说啥都能实现,对不?

大佬说:“我也看着嫌别扭, 你看这样如何?”

张三 := "张三"

“长了一堆小眼睛就可以了?” 你疑惑的问?

大佬说:“Of cource”。于是不屑的扭头走了,挥一挥衣袖,不带走你艳羡的眼神。

“那多个变量声明呢?一个个这样也麻烦。”

大佬:“你还真当自己是甲方爸爸了?自己看去。”

于是你小心翼翼的试了一下:

张三, 李四, 王麻子 := "张三", "李四", "王麻子"

“哇靠,真可以!” 你兴奋的喊着, “变量也就这么回事”。

大佬不屑的瞅了你一眼,甩来一段代码:

package main
var x, y int
var (  // 这种因式分解关键字的写法一般用于声明全局变量
    a int
    b bool
)
var c, d int = 1, 2
var e, f = 123, "hello"
//这种不带声明格式的只能在函数体中出现
//g, h := 123, "hello"
func main(){
    g, h := 123, "hello"
    println(x, y, a, b, c, d, e, f, g, h)
}

你愁眉苦脸的看了看代码,又看了看大佬,不敢吱声了。

大佬缓缓的来了一句,“懂点就可以啦,可以去写点东西啦,没必要一下都搞懂嘛。鲁迅先生不是说了,读书不求甚解。”

你假装很懂的点了点头。

别看大佬了,看我。

我们再去看看其他的。

谁家没有一些瓶瓶罐罐,这些不变的东西,在代码里叫常量。

const LENGTH int = 10
 const WIDTH = 5  
 const (
    Unknown = 0
    Female = 1
    Male = 2
  )

基本上常量也就是这样表示的。

这时候你可能会想一下,有没有假如?

大佬虽然不懂你说的啥,兴匆匆的说,“有,有,不但有假如,还可以循环”。

大佬兴奋的给你演示他的发明, 你看“假如长这样”:

/* 判断条件 */
   if a == 100 {
   /* if 条件语句为 true 执行 */   
    fmt.Printf("a 的值为 100 , b 的值为 200\n" );
   }

"那看上去像菊花的是啥?” 你好奇的问?

大佬有点不悦,“这是注释。知道啥是注释吗?就是说明。写成这样就没人当他是代码了”。

“哦哦” 你似懂非懂的点了点头,“那这就是所谓的假如?”

大佬得意的说,“是啊,他还有其他花样,我给你变变”

/* 判断条件 */
   if a == 100 {
       /* if 条件语句为 true 执行 */
       if b == 200 {
          /* if 条件语句为 true 执行 */
          fmt.Printf("a 的值为 100 , b 的值为 200\n" );
       }
   }

“ 这叫嵌套”, 大佬得意的笑了笑,你正准备张口,大佬拿手一示意,别说话。

/* 判断布尔表达式 */
   if a < 20 {
       /* 如果条件为 true 则执行以下语句 */
       fmt.Printf("a 小于 20\n" );
   } else {
       /* 如果条件为 false 则执行以下语句 */
       fmt.Printf("a 不小于 20\n" );
   }

你抬头看了看大佬,大佬大概看出来你的意思了。他觉得你认为这不够酷。

大佬一下拿出两个法宝:

switch {
      case grade == "A" :
         fmt.Printf("优秀!\n" )    
      case grade == "B", grade == "C" :
         fmt.Printf("良好\n" )      
      case grade == "D" :
         fmt.Printf("及格\n" )      
      case grade == "F":
         fmt.Printf("不及格\n" )
                 fallthrough
      default:
         fmt.Printf("差\n" );
}

你疑惑的说“就知道装神弄鬼,其他的我在其他地方也见过,那个fallthrough 是啥?”

大佬得意的漏出了他的金牙,指了一下,神秘的说 “就因为这个,谷歌给我奖了颗金牙”。

“快说啊,我以前没见过”

“你见过啥?”

“我见过break”

“那都过时了,我这个和它正好相反。我设计的这个,执行完就结束了,不需要break。如果还需要继续执行就加个fallthrough。” “哦哦” ,你假装对大佬竖起大拇指,心里嘀咕着为啥其他人不这么搞,真是老糊涂了。

大佬神秘的说,给你再看个高级的:

var c1, c2, c3 chan int
   var i1, i2 int
   select {
      case i1 = <-c1:
         fmt.Printf("received ", i1, " from c1\n")
      case c2 <- i2:
         fmt.Printf("sent ", i2, " to c2\n")
      case i3, ok := (<-c3):  // same as: i3, ok := <-c3
         if ok {
            fmt.Printf("received ", i3, " from c3\n")
         } else {
            fmt.Printf("c3 is closed\n")
         }
      default:
         fmt.Printf("no communication\n")
   }

“这是?他们是亲戚?”

“嗯,算是吧。不过我改了一下他们的基因”

“有啥用?看着像四不像啊” 大佬得意的笑了笑,捋了捋白色的胡须,“天机不可泄露。知识送给有缘人,来日再见”

果然是神龙见首不见尾,大佬一下子不见了,你只能生硬的记住了这段代码。

由于思考的太过投入,你竟然在原地转起了圈圈。

当你突然意识到自己在转圈圈时,想起来如果我能让代码转圈圈就好了。

隐隐约约你听到大佬的声音:“那不就是循环吗”

你向四周看了看,什么也没有。

空山不见人,但闻人语响。

忽地眼前飘过来一段代码:

sum := 0
        for i := 0; i <= 10; i++ {
                sum += i
        }
        fmt.Println(sum)

你疑惑的看了看,似曾相识。

“i 是个变量,初始化成0, 假如 i 小于等于 10,就循环一次,每循环一下,i 加一” ,你默默的嘀咕着。

你恍惚觉得大佬有点惊讶的看着你。定了定神,原来只是幻觉。

“ i++, 这大佬一看就是懒人啊。i++ 是啥?难道是 i = i+ 1?”

“果然天资聪慧”,大佬赞许的点了点头。

你兴奋的说,“大佬,你神仙啊,你咋回来了”。大佬装模作样的说:“咳咳,嗯..., 算是吧”。

“这个叫 for 循环, i := 0 这个呢是初始化 i,然后呢加一个条件,i <= 10, 最后这个 i++ 和你想的一样,就是没执行一次循环加一”, 大佬继续说道。

大佬看你很轻松,就趁机拿出了for 的几种变化:

sum := 1
        for ; sum <= 10; {
                sum += sum
        }
        // 这样写也可以,更像 While 语句形式
        for sum <= 10{
                sum += sum
        }
        // 这样写也可以
        sum := 0
        for {
            sum++ // 无限循环下去
        }

“ 大佬, 你是不是工作量不饱和啊?” 你坏笑着问大佬。

大佬神情紧张的看了看四周,“嘘,年纪大了,不摸鱼熬不住,大厂也辛苦”。

“还有一种形式,真的有用,不过现在和你说了你也不懂”,大佬继续说道。

不过我可以给你三个法宝,大佬说着从怀里拿出了三样东西:

break 语句 经常用于中断当前 for 循环或跳出 switch 语句 continue 语句 跳过当前循环的剩余语句,然后继续进行下一轮循环。goto 语句 将控制转移到被标记的语句。

“拿好了,关键时候需要。不然你会吃亏的” ,大佬神神秘秘的说着。

你拍了拍灰尘,小心的收好了。

相关文章
|
3天前
|
程序员 Go PHP
为什么大部分的 PHP 程序员转不了 Go 语言?
【9月更文挑战第8天】大部分 PHP 程序员难以转向 Go 语言,主要因为:一、编程习惯与思维方式差异,如语法风格和编程范式;二、学习成本高,需掌握新知识体系且面临项目压力;三、职业发展考量,现有技能价值及市场需求不确定性。学习新语言虽有挑战,但对拓宽职业道路至关重要。
28 10
|
1天前
|
Go API 开发者
深入探讨:使用Go语言构建高性能RESTful API服务
在本文中,我们将探索Go语言在构建高效、可靠的RESTful API服务中的独特优势。通过实际案例分析,我们将展示Go如何通过其并发模型、简洁的语法和内置的http包,成为现代后端服务开发的有力工具。
|
3天前
|
算法 程序员 Go
PHP 程序员学会了 Go 语言就能唬住面试官吗?
【9月更文挑战第8天】学会Go语言可提升PHP程序员的面试印象,但不足以 solely “唬住” 面试官。学习新语言能展现学习能力、拓宽技术视野,并增加就业机会。然而,实际项目经验、深入理解语言特性和综合能力更为关键。全面展示这些方面才能真正提升面试成功率。
21 10
|
3天前
|
编译器 Go
go语言学习记录(关于一些奇怪的疑问)有别于其他编程语言
本文探讨了Go语言中的常量概念,特别是特殊常量iota的使用方法及其自动递增特性。同时,文中还提到了在声明常量时,后续常量可沿用前一个值的特点,以及在遍历map时可能遇到的非顺序打印问题。
|
7天前
|
安全 大数据 Go
深入探索Go语言并发编程:Goroutines与Channels的实战应用
在当今高性能、高并发的应用需求下,Go语言以其独特的并发模型——Goroutines和Channels,成为了众多开发者眼中的璀璨明星。本文不仅阐述了Goroutines作为轻量级线程的优势,还深入剖析了Channels作为Goroutines间通信的桥梁,如何优雅地解决并发编程中的复杂问题。通过实战案例,我们将展示如何利用这些特性构建高效、可扩展的并发系统,同时探讨并发编程中常见的陷阱与最佳实践,为读者打开Go语言并发编程的广阔视野。
|
4天前
|
存储 Shell Go
Go语言结构体和元组全面解析
Go语言结构体和元组全面解析
|
9天前
|
存储 Go
Golang语言基于go module方式管理包(package)
这篇文章详细介绍了Golang语言中基于go module方式管理包(package)的方法,包括Go Modules的发展历史、go module的介绍、常用命令和操作步骤,并通过代码示例展示了如何初始化项目、引入第三方包、组织代码结构以及运行测试。
17 3
|
4月前
|
开发框架 安全 中间件
Go语言开发小技巧&易错点100例(十二)
Go语言开发小技巧&易错点100例(十二)
55 1
|
1月前
|
JSON 中间件 Go
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
本文详细介绍了如何在Go项目中集成并配置Zap日志库。首先通过`go get -u go.uber.org/zap`命令安装Zap,接着展示了`Logger`与`Sugared Logger`两种日志记录器的基本用法。随后深入探讨了Zap的高级配置,包括如何将日志输出至文件、调整时间格式、记录调用者信息以及日志分割等。最后,文章演示了如何在gin框架中集成Zap,通过自定义中间件实现了日志记录和异常恢复功能。通过这些步骤,读者可以掌握Zap在实际项目中的应用与定制方法
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
|
30天前
|
算法 NoSQL 中间件
go语言后端开发学习(六) ——基于雪花算法生成用户ID
本文介绍了分布式ID生成中的Snowflake(雪花)算法。为解决用户ID安全性与唯一性问题,Snowflake算法生成的ID具备全局唯一性、递增性、高可用性和高性能性等特点。64位ID由符号位(固定为0)、41位时间戳、10位标识位(含数据中心与机器ID)及12位序列号组成。面对ID重复风险,可通过预分配、动态或统一分配标识位解决。Go语言实现示例展示了如何使用第三方包`sonyflake`生成ID,确保不同节点产生的ID始终唯一。
go语言后端开发学习(六) ——基于雪花算法生成用户ID