关键字、标识符

标识符:

是用户或系统定义的有意义单词组合,或单词与数字组合(具体意义有定义者决定)  

标识符以字母下划线开头,大小写敏感,比如:boy,  Boy,  _boy,  _(匿名变量,用来忽略结果)

标识符命名规范:在习惯上,Go语言程序员推荐使用驼峰式命名,当名字有几个单词组成的时优先使用大小写分隔,而不是优先用下划线分隔。因此,在标准库有QuoteRuneToASCII和parseRequestLine这样的函数命名,但是一般不会用quote_rune_to_ASCII和parse_request_line这样的命名。而像ASCII和HTML这样的缩略词则避免使用大小写混合的写法,它们可能被称为htmlEscape、HTMLEscape或escapeHTML,但不会是escapeHtml。

关键字:

是 Go 语言提供的有特殊含义的符号,也叫做“保留字”

系统保留关键字:

break default func interface select
case defer go map struct
chan else goto package switch
const fallthough if range type
continue for import return var

常量与变量

常量

常量使用 const 修饰,表示是只读的,不能修改

const 只能修饰 boolean,number(int相关,浮点数,complex)和 string 类型

语法:const identifier [type] = value(type 可省略)

优雅写法:

const(
name string = "skier"
age int = 10
salary int = 5000 / 2
// gender boolean = getGender() // const不能从函数中获取

常量因为在编译期确定,所以可以用于数组声明:

const size = 4
var arrayA [size]int

变量

声明一个变量:var identifier [type]

// 声明变量并赋值
var a int = 100 // 简写(自动推导类型)
a := 100

优雅写法:

var (
name string = "johny"
age int = 10
)

默认值:

  • int        0
  • float     0.0,编译默认推导为 float64
  • bool     false
  • string   ""  
  • slice,函数,指针变量默认为 nil  (slice 默认为 nil,但打印输出是 [],可使用 == nil 进行判空)

作用域:从定义变量的代码行开始,一直到直接所属的大括号结束为止(全局变量除外)

  • 在函数部声明的变量叫做局部变量,生命周期仅限于函数内部
  • 在函数部声明的变量叫做全局变量,生命周期作用于整个包,如果首字母大写的话,则可以被其它包导入

在编程中,变量在其实现了变量的功能后,作用范围越小,所造成的问题可能性越小,每一个变量代表一个状态,有状态的地方,状态就会被修改,函数的局部变量只会影响一个函数的执行,但全局变量可能会影响所有代码的执行状态,因此限制变量的作用范围对代码的稳定性有很大的帮助

基本数据类型与操作符

数字类型:int8,  int16,  int32,  int64,  uint8,  uint16, uint32,  uint64

bool 类型:ture,  false  (bool 型无法参与数值运算,也无法与其他类型进行转换。)

浮点类型:float32,  float64

字符类型:byte

字符串类型:字符串实现基于 UTF-8 编码

  ""  双引号,定义行字符串

  ``  反引号,定义行字符串(在这种方式下,反引号间换行将被作为字符串中的换行,但是所有的转义字符均无效,文本将会原样输出)

    多行字符串一般用于内嵌源码和内嵌数据等

类型转换

格式:type(variable)

var a  int = 8
var b int32 = int32(a) 

浮点数转换成 int 类型,精度会丢失

var c float32 = math.Pi
fmt.Println(int(c))

int32 转换成 int16,数据会截断

// 初始化一个32位整型值
var a int32 = 1047483647
// 输出变量的十六进制形式和十进制值
fmt.Printf("int32: 0x%x %d\n", a, a) // 将a变量数值转换为十六进制, 发生数值截断
b := int16(a)
// 输出变量的十六进制形式和十进制值
fmt.Printf("int16: 0x%x %d\n", b, b) 结果是:
int32: 0x3e6f54ff 1047483647
int16: 0x54ff 21759

字符串转义符

转移符 含  义
\r 回车符(返回行首)
\n 换行符(直接跳到下一行的同列位置)
\t 制表符
\' 单引号
\" 双引号
\\ 反斜杠

操作符

数字操作符:+,  -,  *,  /,  %

比较运算符:>,  >=,  <,  <=,  ==,  !=

字符串操作

拼接:

var str1 string = "hello"
var str2 string = "world"
var str string = str1 + str2 // var str string = fmt.Sprintf("%s%s", str1, str2)
 
获取长度:var length int = len(str)
 
切片:var substr string = str[:5]  (与python类似)

值类型与引用类型

值类型

本质上是原始类型,变量直接储存值,内存通常在中分配,包括 int,  float,  bool,  string 以及数组和 struct(结构体)

对值类型进行操作,一般都会返回一个新创建的值,所以把这些值传递给函数时,其实传递的是一个值的副本

func main() {
name:="张三"
fmt.Println(modify(name))
fmt.Println(name)
} func modify(s string) string{
s=s+s
return s
} //Output
张三张三
张三

以上是一个操作字符串的例子,通过打印的结果,可以看到,本来 name 的值并没有改变,也就是说,我们传递的是一个副本,并且返回一个新创建的字符串

基本类型因为是值的拷贝,并且在对他进行操作的时候,生成的也是新创建的值,所以这些类型在多线程里是安全的,我们不用担心一个线程的修改影响了另外一个线程的数据

引用类型

引用类型与值类型恰恰相反,它的修改可以影响到任何引用到它的变量;变量存储的是地址,这个地址存储最终的值,通常在内存上分配,通过 GC 回收,包括 指针,select,map,chan 等

引用类型之所以可以引用,是因为我们创建引用类型的变量,其实是一个标头值,标头值里包含一个指针,指向底层的数据结构,当我们在函数中传递引用类型时,其实传递的是这个标头值的副本,它所指向的底层结构并没有被复制传递,这也是引用类型传递高效的原因。

流程控制

if else 分支判断

if condition1 {
block1
} else if condition2 {
block2
} else {
block3
}

switch case 语句

func main(){
var variabel string = "a"
switch variabel {
case "a", "b":
fmt.Println(variabel)
// fallthrough // 会执行下一个case的语句块
case "c":
fmt.Println(variabel)
default:
fmt.Println("default output")
}
}

case 后边的值可以写多个,是 或 的关系

case 语句块末尾如果加上 fallthrough,会接着执行下一个 case 的语句块

 

for 循环

for i:=0; i<100 ; i++ {
fmt.Println("hello, world~")
}

死循环(for)

func main(){
for {
fmt.Println("hello, world~")
time.Sleep(time.Second)
}
}

加判断的 for 循环

func main(){
var i int
for i<100 {
fmt.Println(i)
i += 1
}
}

for range 语句

可以使用 for range 遍历数组、切片、字符串、map 及通道(channel)。通过 for range 遍历的返回值有一定的规律:

  • 数组、切片、字符串返回索引和值
  • map 返回键和值
  • 通道(channel)只返回通道内的值

遍历数组:

var arrayA = [3]string{"hammer", "soldier", "mum"}

for index, value := range arrayA {
fmt.Println(index, value)
} 运行结果:
0 hammer
1 soldier
2 mum

用匿名标识符忽略 index

var arrayA = [3]string{"hammer", "soldier", "mum"}

for _, value := range arrayA {
fmt.Println(value)
} 运行结果:
hammer
soldier
mum

当然,for 循环中也能够支持:break,  continue

goto 语句

可以通过标签进行代码间的无条件跳转,goto语句可以快速跳出循环 或 实现同样的逻辑 有一定的帮助:

快速跳出循环:

func main(){
for i:=0; i<=100; i++{
for j:=0; j<=100; j++{
if j == 10 {
// 直接跳转到标签
goto breakHere
}
}
} breakHere:
fmt.Println("hello world~")
} 运行结果:
hello world~

  

使用 goto 集中处理错误:

err := firstCheckError()
if err != nil {
goto onExit
} err = secondCheckError()
if err != nil {
goto onExit
} fmt.Println("done")
return onExit:
fmt.Println(err)
exitProcess()

函数

Go 语言支持普通函数、匿名函数和闭包

普通函数声明:func 函数名(参数列表)  (返回值列表)  {函数体}

不支持重载,一个源文件内不能有两个相同名称的函数

函数是一等公民,也是一种类型,可以赋值给变量

函数的传参方式

  • 值传递        (基本数据类型都是值传递)
  • 引用传递          (指针,slice,map,chan,interface)

注意:无论是值传递还是引用传递,传递给函数的都是变量的副本,不过,值传递是对值的拷贝,引用传递是地址的拷贝,一般来说,地址拷贝更为高效,而值拷贝取决于拷贝对象的大小,对象越大,则性能越低

返回值命名

返回值不需要定义,直接使用(命名的返回值变量的默认值为类型的默认值,即数值为 0,字符串为 "",布尔为 false、指针为 nil)

func calc(a int, b int) (c int) {
c = a + b
return c
}

可变长参数

可变参数变量是一个包含所有参数的切片

func calc(a int, b int, arg... int) {
fmt.Println(arg[0])
}

defer 的用途

  1. 延迟调用是在 defer 所在函数结束时进行,函数结束可以是正常返回时,也可以是发生宕机
  2. 多个 defer 语句,按先进后出(栈)的顺序执行
  3. defer 语句中的变量,在 defer 声明时就决定了
  4. defer 语句正好是在函数退出时执行的语句,所以使用 defer 能非常方便地处理资源释放问题

关闭文件句柄

注意:不能将这一句代码放在第3行空行处,一旦文件打开错误,f将为空,在延迟语句触发时,将触发宕机错误

func read(){
file err := open(filename)
if err != nil{
return
}
defer file.Close()
}

锁资源的释放

func lock(){
mc.Lock()
defer mc.Unlock()
}

数据库连接的释放

func connect(){
conn := openDatabase()
defer conn.Close()
}

调用函数

函数在定义后,可以通过调用的方式,让当前代码跳转到被调用的函数中进行执行。调用前的函数局部变量都会被保存起来不会丢失;被调用的函数结束后,恢复到被调用函数的下一行继续执行代码,之前的局部变量也能继续访问

递归函数

一个函数在内部调用自己,就叫做递归,下面来举两个递归函数的Demo

递归求阶乘

func calc(n int) int {
if n <= 1{
return 1
} return calc(n-1) * n
} func main(){
result := calc(5)
fmt.Println(result)
} 运行结果:
120

斐波拉契数

func fab(n int) int {
if n<=1{
return 1
} return fab(n-1) + fab(n-2) } func main(){
var n int = 6
var fabCount int
for i:=0; i<=n; i++{
fabCount += fab(i)
} fmt.Println(fabCount)
} 运行结果:
33

匿名函数

匿名函数没有函数名,只有函数体,可以直接被当做一种类型赋值给函数类型的变量,匿名函数也往往以变量的方式被传递

匿名函数经常被用于实现回调函数、闭包

定义一个匿名函数

func(str string){
fmt.Println("hello", str)
}("world") 运行结果:
hello world

也可以将匿名函数赋值给变量

f := func(str string){
fmt.Println("hello", str)
} f("world")

匿名函数当做参数

func visit(sliceA []int, f func(int)){
for _, value := range sliceA {
f(value)
}
} func main(){
var sliceA []int = []int{1,2,3,4,5} f := func(a int){
fmt.Print(a)
}
visit(sliceA, f)
} 运行结果:
12345

使用匿名函数实现操作封装

func main(){
var mapA map[string]func()
mapA = map[string]func(){
"fire": func(){
fmt.Println("chicken fire")
},
"run": func(){
fmt.Println("soldier run")
},
"fly": func(){
fmt.Println("angel fly")
},
}
// fmt.Println(mapA)
// 接收命令行参数,key,默认值,帮助
var skill *string = flag.String("skill", "", "skill type")
flag.Parse() f, err := mapA[*skill]
if err == true {
f()
} else {
fmt.Println("skill not fount")
}
} 运行效果:
$ go run main.go --skill=fly
angel fly
$ go run main.go --skill=run
soldier run

闭包(Closure)

闭包是引用了自由变量的函数,被引用的自由变量和函数一同存在,即使已经离开了自由变量的环境 也不会被释放或者删除,在闭包中可以继续使用这个自由变量(闭包(Closure)在某些编程语言中也被称为 Lambda 表达式)

简单的说:

闭包 = 函数 + 引用环境

同一个函数与不同的引用环境组合,可以形成不同的实例,如图:

实现一个简单的闭包

func closureFunc(str string) func(){
wapper := func(){
fmt.Println("hello", str)
}
return wapper
} func main(){
f := closureFunc("world~")
// 调用闭包函数
f()
} 运行结果:
hello world~

累加器的实现(闭包的记忆效应)

func accumulate(num int) func() int {
wapper := func() int {
num += 1
return num
}
return wapper
} func main(){
accumulator := accumulate(10)
ret1 := accumulator()
fmt.Println(ret1)
ret2 := accumulator()
fmt.Println(ret2)
} 运行结果:
11
12

go 基本程序结构

// 任何一个代码源文件隶属于一个包
package main //import 关键字,同一个包内的函数可以直接调用,不同包中的函数通过 包名.函数名 的方式调用
import (
"fmt"
"/go_dev/test"
) // 初始化函数
func init(){
fmt.Println("执行初始化操作")
} // main 程序入口
func main(){
fmt.Println("hello, world~")
}

init 函数

每个源文件都可以包含一个 init 函数,会自动被编译器执行

包访问控制规则

    1. 包内函数名首字母大写表示此函数/变量是可导出的
    2. 小写表示此函数/变量是私有的,在包外部不能访问

程序执行顺序(栈)  *

  1. 导入其它包,初始化 被导入包 内的全局变量,执行 被导入包 内所有源文件的 init 函数
  2. 初始化 main 包内全局变量
  3. 调用 main 包 init 函数
  4. 执行 main 函数

练习1:写一个函数,对于一个整数n,求出所有两两相加等于n的组合,比如 n=5

package main

import (
"fmt"
) func calc(n int){
for i:=0; i<=n; i++ {
num := n - i
fmt.Printf("%d+%d=%d\n", i, num, n)
} } func main(){
calc(5)
} 结果:
0+5=5
1+4=5
2+3=5
3+2=5
4+1=5
5+0=5

练习2:一个程序包含 add 和 main 两个包,add 包中有两个变量 Name 和 age,在 main 中访问 Name 和 age 变量,打印输出

首先在 go_dev 下新建一个目录 example(go_dev 目录在环境变量 GOPATH 下 src 目录,go编译器根据系统路径会找到 go_dev 目录下的包)

add包下写 add.go

package add

var Name string = "skier"
var age int = 19

main包下写 main.go

package main

import (
"go_dev/example/add"
// a "go_dev/example/add" // 包别名的应用
"fmt"
) func main(){
fmt.Println(add.Name)
fmt.Println(add.age) // 不能访问
}

作业

1.判断101~200之间有多少个素数,并输出打印

package main

import (
"fmt"
) func main(){
for i:=101; i<=200; i++{
var flag bool = true
for j:=2; j<i; j++{
if (i % j == 0) {
flag = false
}
}
if (flag == true){
fmt.Println("素数i:", i)
}
}
}

第一题

2.打印出101~999中所有的水仙花数,所谓水仙花数是指一个三位数,其各位数字的立方和等于该数本身,例如153是一个水仙花数,1*1*1 + 5*5*5 + 3*3*3 = 153

package main

import (
"fmt"
) func narcissisticNum(num int) bool {
var g int = num % 100 % 10
var s int = num % 100 / 10
var b int = num / 100
//fmt.Println(g, s, b)
var cube int = g*g*g + s*s*s + b*b*b
return num == cube
} func main(){
for i:=100; i<=999; i++{
result := narcissisticNum(i)
if result == true {
fmt.Println("水仙花数是:", i)
}
}
}

第二题

3.对于一个数n,求n的阶乘之和,即:1! + 2! + ... + n!

package main

import (
"fmt"
) func summation(n int) int {
var result int
for i:=1; i<=n; i++ {
var tmpe int = 1
for j:=1; j<=i; j++{
tmpe *= j
}
result += tmpe
}
return result
} func main(){
var num int = 5
var result int = summation(num)
fmt.Println("sum result:", result)
}

第三题

4.在终端打印 9*9 乘法表

package main

import(
"fmt"
) func multiplication(){
for column:=1; column<=9; column++{
for row:=1; row<=column; row++{
fmt.Printf("%d*%d=%d\t", column, row, column*row)
}
fmt.Println()
}
} func main(){
multiplication()
}

第四题

5.一个数如果恰好等于它的因子之和,这个数就称之为“完数”,例如:1+2+3=6,在终端输出1000以内的所有完数

package main

import(
"fmt"
) func showPerfect(n int){
for i:=1; i<n; i++{
var sum int for j:=1; j<i; j++{
if i % j == 0{
sum += j
}
} if sum == i{
fmt.Printf("完数:%d \n", i)
}
}
} func main(){
const num int = 1000
showPerfect(num)
}

第五题

6.输入一个字符串,判断其是否为“回文”,回文字符串是指从左到右读,与从右到左读是完全相同的字符串

package main

import (
"fmt"
) func isReverse(str string) bool {
// 转为字符
char := []rune(str) var length int = len(char) for i:=0; i<=length / 2 - 1; i++{
if char[i] != char[length-1-i]{
return false
}
} return true
} func main(){
var input string
fmt.Scanf("%s", &input)
result := isReverse(input)
fmt.Println("result:", result)
}

第六题

7.输出一行字符串,分别统计其中英文字母,空格,数字和其它符号的个数

package main

import (
"fmt"
"bufio"
"os"
) func count(str string) (wordCount, spaceCount, numCount, otherCount int) {
chars := []rune(str)
for _, value := range chars{
switch {
case value >= 'a' && value <= 'z':
wordCount += 1
case value >= 'A' && value <= 'Z':
wordCount += 1
case value == ' ':
spaceCount += 1
case value >= '0' && value <= '9':
numCount += 1
default:
otherCount += 1
}
}
return
} func main(){
reader := bufio.NewReader(os.Stdin)
// 读取一行的内容
result, _, error := reader.ReadLine() if error == nil{
wordCount, spaceCount, numCount, otherCount := count(string(result))
fmt.Printf("wordCount:%d\nspaceCount:%d\nnumCount:%d\notherCount:%d\n", wordCount, spaceCount, numCount, otherCount)
}
}

第七题

8.计算两个大数相加的和,这两个大数会超过 int64 的表示范围

Go part 2 基础语法的更多相关文章

  1. Swift与C#的基础语法比较

    背景: 这两天不小心看了一下Swift的基础语法,感觉既然看了,还是写一下笔记,留个痕迹~ 总体而言,感觉Swift是一种前后端多种语言混合的产物~~~ 做为一名.NET阵营人士,少少多多总喜欢通过对 ...

  2. iOS-----正则表达式的基础语法

    正则表达式简单语法总结 一.什么是正则表达式 从概念上来说,正则表达式也是一门小巧而精炼的语言,它可以用来简化检索特定的字符串,替换特定字符等功能,有许多开发语言工具,都内嵌支持正则表达式.那么一个正 ...

  3. python之最强王者(2)——python基础语法

    背景介绍:由于本人一直做java开发,也是从txt开始写hello,world,使用javac命令编译,一直到使用myeclipse,其中的道理和辛酸都懂(请容许我擦干眼角的泪水),所以对于pytho ...

  4. emmet 系列(1)基础语法

    emmet 系列(1)基础语法 emmet 是一个能显著提升开发html和css开发效率的web开发者工具 emmet基本上目前已知的编辑器都有相应的插件,各个编辑器的emmet插件的下载地址:点我下 ...

  5. Scala基础语法 (一)

    如果你之前是一名 Java 程序员,并了解 Java 语言的基础知识,那么你能很快学会 Scala 的基础语法. Scala 与 Java 的最大区别是:Scala 语句末尾的分号 ; 是可选的. 我 ...

  6. Java基础语法

    java基础学习总结——基础语法1 一.标识符

  7. javascript中正则表达式的基础语法

    × 目录 [1]定义 [2]特点 [3]元字符[4]转义字符[5]字符组[6]量词[7]括号[8]选择[9]断言[10]模式[11]优先级[12]局限性 前面的话 正则表达式在人们的印象中可能是一堆无 ...

  8. Swift基础语法学习总结(转)

    Swift基础语法学习总结 1.基础  1.1) swift还是使用// 和/* */ 来注释,并且/* */允许多行注释. 1.2) swift使用print和println打印,它的传参是一个泛型 ...

  9. 黑马程序员——OC语言基础语法 面向对象的思想

    Java培训.Android培训.iOS培训..Net培训.期待与您交流! (以下内容是对黑马苹果入学视频的个人知识点总结)(一)基础语法 1)关键字 @interface.@implementati ...

  10. 【OC基础语法考试】

    OC基础语法已经全部学完,但是这些知识只是最基础的,还有很多高级知识,这个可能需要后面慢慢的去学习才能体会到.接下来我会总结前面的OC基础语法,如果大家发现有什么不正确的地方,请指正,小弟是新生,多请 ...

随机推荐

  1. 【422】Insert often-used pieces of text in gedit

    Ref: Snippets Enable Snippets Plugin Browse Snippets Using Snippets To insert a nippet into your cur ...

  2. PAT 甲级 1051 Pop Sequence (25 分)(模拟栈,较简单)

    1051 Pop Sequence (25 分)   Given a stack which can keep M numbers at most. Push N numbers in the ord ...

  3. Apache三种工作模式详解

    Apache HTTP服务器被设计为一个强大的.灵活的能够在多种平台以及不同环境下工作的服务器.这种模块化的设计就叫做“多进程处理模块”(Multi-Processing Module,MPM),也叫 ...

  4. 【ARTS】01_33_左耳听风-201900624~201900630

    ARTS: Algrothm: leetcode算法题目 Review: 阅读并且点评一篇英文技术文章 Tip/Techni: 学习一个技术技巧 Share: 分享一篇有观点和思考的技术文章 Algo ...

  5. charles 查找

    本文参考:charles 查找 查找设置 界面如上图,也没啥好说的: 这个还是非常常用的:需要了解 界面如上图,也没啥好说的: 这个还是非常常用的:需要了解 查找需要了解的关键字是: 查找的内容 正则 ...

  6. 前端添加视频流rtmp格式

    要求:rtmp格式, 在线直播 url地址 效果: 代码:初次打开时间较长, <!DOCTYPE html> <html> <head> <script ty ...

  7. 删除Excel表格中一堆英文中的汉字

    昨天需要处理一个Excel文件,删除一堆英文里的汉字,开始搜了下方法,没找到,然后手动一个多小时,弄了一半吧也就,结果电脑卡了,忘了保存,就白做了...不知道为啥这次没有自动保存,所以,重要的事说三遍 ...

  8. table列表全选

    <table><tr><td><input type="checkbox" /></td><td></ ...

  9. python从hello world开始 - python基础入门(3)

    万丈高楼平地起,编程亦如此.改变世界是结果,坚持努力学习改bug是过程,hello world是开始,所有语言均是如此. 一.使用pycharm创建第一个hello world 项目 1.Create ...

  10. Clustering and Exploring Search Results using Timeline Constructions (paper2)

    作者:Omar Alonso 会议:CIKM 2009 摘要: 截至目前(2009),通过提取文档中内嵌的时间信息来展现和聚类,这方面的工作并不多. 在这篇文章中,我们将提出一个“小插件”增添到现有的 ...