一、hello world
package main //每个go文件都以package字句开头,package字句给出包的名称,Go文件中的代码称为包的一部分。
import "fmt" //每个文件都需要导入其他包,然后才能使用其他包里包含的代码
func main () {
fmt.Println("Hello World!","Go") //参数用,号分隔
}
package main
import (
"fmt" //包名
"math"
"strings"
)
func main() {
fmt.Println(math.Floor(3.14)) //通过包调用函数,例如fmt(包).Println(函数)()
fmt.Println(strings.Title("head first go"))
}
字符串
“Hello World!”
符文(rune)
‘A’ //单个字符
布尔值
true,false
声明变量
只需要使用var关键字,后跟所需的名称以及变量将要保存值的类型。
var quality int
var length,width float64
var name string
//用=为变量分配该类型的任何值
quality=2
name="go"
//可以一次为多个变量赋值
length,width=1.2,2.4
//如果在声明变量的同时为其赋值,通常可以在声明中省略变量的类型。分配给变量的值类型将用作该变量的类型。
var quality=2
var length,width=1.2,1.4
var name="go"
短变量声明
如果声明变量的时候就知道其值是什么,可以使用短变量声明。不必很明确地声明变量的类型并在之后使用=为其赋值,而是同时使用:=。这里如果忽略了:,quality=2将被视为赋值。
quality:=2 //声明加定义(同时赋值)
length,width:=1.2,2.4
name:="go"
所有声明的变量都必须在程序中使用。
fmt.Println(quality)
fmt.Println(length,width)
fmt.Println(name)
类型
可以通过将任何值传递给reflect包的TypeOf函数,来查看他们的类型。
package main
import (
"fmt"
"reflect"
)
func main() {
fmt.Println(reflect.TypeOf(42)) //int
}
命名规则
- 名称必须以大写字母开头
如果变量、函数或类型的名称以大写字母开头,则认为它是导出的,可以从当前包之外访问它,否则只能在当前包中使用。
转换
Go中的数学运算和比较运算要求包含的值具有相同类型。 如果不是的话,则在尝试运行代码时会报错。为变量分配新值也是如此,所赋值的类型与变量申明的类型不匹配也会报错。
转换的目的是允许你将值从一种类型转换为另一种类型。只需提供要将值转换成的类型,后面紧接着是圆括号中要转换的值。
var myInt int = 2
float64(myInt)
quality:=2
length:=1.2
length=float64(quality)
二、条件和循环
调用方法
Go中方法是指:与给定类型的值相关联的函数。有点像成员函数。
在下面的代码中time包中有一个表示日期和时间的Time类型,每一个time.Time值都有一个返回年份的Year方法。
package main
import (
"fmt"
"time"
)
func main() {
//time.Now函数返回当前日期和时间的新Time值,将其存储在now变量中。然后对now引用的值调用Year方法。
var now time.Time = time.Now()
var year int = now.Year()
fmt.Println(year)
fmt.Println(now)
}
方法是与特定类型的值关联的函数。
string包有一个Replacer类型,可以在字符串中搜索子字符串,并且在每次该子字符串出现的地方用另一个字符串替换它:
package main
import (
"fmt"
"strings"
)
func main() {
broken:="G# r#cks!"
replacer:=strings.NewReplacer("#","o") //将返回strings.Replacer,并设置为将每个"#"替换为"o"
fixed:=replacer.Replace(broken)//strings.Replacer调用Replace方法,并传递一个字符串进行替换
fmt.Println(fixed)
}
调用方法与函数有什么区别?
函数属于一个包,而方法属于一个单独的值。这个值出现在圆点的左边。
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
fmt.Print("Enter a grade: ")
//需要从程序的标准输入中读取输入的方法
//input, _ := (bufio.NewReader(os.Stdin)).ReadString('\n') //正常输出
reader:=bufio.NewReader(os.Stdin) //将bufio.Reader保存在reader变量中
input:=reader.ReadString('\n') //为了实际获取用户输入,调用Reader的ReaderString方法,ReadString方法需要一个带有rune的参数来标记输入结束,也就是说换行符前的所有内容都将被读取
fmt.Println(input)
}
上述代码中ReadString方法试图返回两个值,实际上运行会报错。
Go中多个返回值最常见的用法是返回一个额外的错误值(err),可以通过查询该错误值来确定函数或方法是否发生了错误。
Go要求声明的每个变量都必须在程序的每个地方使用。如果我们添加了一个err变量,而不检查它,我们的代码将无法通过编译。
代码改进为:
input,err := reader.ReadString('\n') //错误,Go不允许我们声明一个变量,除非我们使用它。
//使用Go的空白标识符忽略错误返回值
input,_ := reader.ReadString('\n')
还可以选择对错误进行处理:添加log包,其中Fatal函数,可以同时为我们完成两项操作:将一条消息记录到终端并停止程序运行。
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
fmt.Print("Enter a grade: ")
//需要从程序的标准输入中读取输入的方法
reader:=bufio.NewReader(os.Stdin) //将bufio.Reader保存在reader变量中
input,err:=reader.ReadString('\n') //为了实际获取用户输入,调用Reader的ReaderString方法,ReadString方法需要一个带有rune的参数来标记输入结束,也就是说换行符前的所有内容都将被读取
log.Fatal(err)
fmt.Println(input)
}
条件
运行时我们发现即使程序正常也会停止运行。返回只err为nil,则表示没有错误。但是我们的程序只简单报告nil错误,我们应该做的是,只有当err变量的值不是nil时才退出程序。
实现这一点可以使用条件语句。
input,err:=reader.ReadString('\n')
if err!=nil {
log.Fatal(err)
}
fmt.Println(input)
将字符串转换为数字
试着写下这样的代码看看会有什么问题。
func main() {
fmt.Print("Enter a grade: ")
reader:=bufio.NewReader(os.Stdin)
input,err:=reader.ReadString('\n')
if err!=nil {
log.Fatal(err)
}
if input >=60 {
status:="passing"
} else {
status:="failing"
}
}
从键盘输入的内容是作为字符串读入的。上述存在两个问题:
- 输入的字符串末尾有一个换行符
- 剩下的字符串需要转换为浮点数
解决办法: - strings包里有一个TrimSpace函数,它将删除字符串开头和结尾的所有空白字符(换行符、制表符和常规空格)
input=strings.TrimSpace(input)
- strconv包的ParseFloat函数将其转换为float64值
grade,err:=strconv.ParseFloat(input,64)
64为结果的精度位数
块
Go代码可以分块,即代码段。块通常由大括号{}包围,块可以嵌套。如上面代码中,有if块,函数块,包块以及文件块。
块和变量的作用域
声明的变量都有一个作用域:代码中的可见部分。声明的变量可以在其作用域内的任何地方被访问,但是如果在作用域之外访问它,就会收到一个错误。
上面status作用域局限在if块中,在作用域之外访问status会发生错误。
下面给出一个完整的成绩判断程序:
package main
import (
"fmt"
"os"
"bufio"
"log"
"strings"
"strconv"
)
func main() {
fmt.Print("Enter a grade: ")
reader:=bufio.NewReader(os.Stdin)
input,err:=reader.ReadString('\n')
if err!=nil {
log.Fatal(err)
}
input=strings.TrimSpace(input)
grade,err:=strconv.ParseFloat(input,64)
if err!=nil {
log.Fatal(err)
}
var status string
if grade >=60 {
status="passing"
} else {
status="failing"
}
fmt.Println(grade,"is",status)
}
短变量声明中只有一个变量必须是新的
当一个变量名在同一作用域中被声明两次时。我们会得到一个编译错误:
a:=1
a:=2
但是只要短变量声明中至少有一个变量名是新的(没有声明过),这是允许的。新变量名被视为声明,而现有的名字被视为赋值。
a:=1 //声明a
b,a:=2,3 //声明b,赋值a
a,c:=4,5 //赋值a,声明c
一个猜数字的小游戏
//guess challenge players to guess a random number
package main
import (
"bufio"
"fmt"
"log"
"math/rand"
"os"
"strconv"
"strings"
"time"
)
func main() {
seconds := time.Now().Unix() // time.Now()会返回表示当前日期的Time值,Time调用unix方法,它将把时间转换成整数
rand.Seed(seconds) // 播种随机种子生成器
target := rand.Intn(100) + 1 // rand.Intn(100)将返回0~99范围的随机数
fmt.Println("I've chosen a random number between 1 and 100.")
fmt.Println("Can you guess it")
//fmt.Println(target)
reader := bufio.NewReader(os.Stdin)
success := false
for i := 0; i < 10; i++ {
fmt.Println("You have", 10-i, "guesses left!")
fmt.Println("Make a guess: ")
input, err := reader.ReadString('\n')
if err != nil {
log.Fatal(err)
}
input = strings.TrimSpace(input) //删除换行符
guess, err := strconv.Atoi(input) //换成整形
if err != nil {
log.Fatal(err)
}
if guess > target {
fmt.Println("Your guess was HIGH!")
} else if guess < target {
fmt.Println("Your guess was Low!")
} else {
fmt.Println("Your guess was right!")
success = true
break
}
}
if !success {
fmt.Println("Sorry, you didn't guess my number. It was", target)
}
}