/**
*第一行代码 package main 定义了包名。
*你必须在源文件中非注释的第一行指明这个文件属于哪个包,
*如:package main。package main表示一个可独立执行的程序,
*每个 Go 应用程序都包含一个名为 main 的包。
*/
package main
//告诉 Go 编译器这个程序需要使用 fmt 包
import "fmt"
/*
func main() 是程序开始执行的函数。
main 函数是每一个可执行程序所必须包含的,
一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。
当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,
那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),
这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,
则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected )
go run Hello.go
*/
func main() {
/*
变量声明
第一种,指定变量类型,声明后若不赋值,使用默认值。
var v_name v_type
v_name = value
第二种,根据值自行判定变量类型。
var v_name = value
第三种,省略var, 注意 :=左侧的变量不应该是已经声明过的,否则会导致编译错误。
v_name := value,这种只能在函数体中出现
// 例如
var a int = 10
var b = 10
c : = 10
var ( // 这种因式分解关键字的写法一般用于声明全局变量
a int
b bool
)
*/
fmt.Println("Hello, World!")
}
package main
import (
"fmt"
"reflect"
"errors"
)
//定义结构体
type Books struct {
title string
author string
subject string
book_id int
}
//定义接口
type Phone interface {
call()
}
//定义结构体
type NokiaPhone struct {
}
/*
实现接口方法
方法的签名类似:func printBook( book *Books ) {}
但是实现接口方法在方法名前面要加结构体对象和结构体类型
*/
func (nokiaPhone NokiaPhone) call() {
fmt.Println("I am Nokia, I can call you!")
}
func main() {
/*
type 可选
const identifier [type] = value
常量可以用len(), cap(), unsafe.Sizeof()函数计算表达式的值。常量表达式中,函数必须是内置函数,否则编译不过:
import "unsafe"
const (
a = "abc"
b = len(a)
c = unsafe.Sizeof(a)
)
在每一个const关键字出现时,被重置为0,然后再下一个const出现之前,每出现一次iota,其所代表的数字会自动增加1。
iota 可以被用作枚举值:
const (
a = iota //0
b = iota //1
c = iota //2
)
简写
const (
a = iota
b
c
)
const (
a = iota //0
b //1
c //2
d = "ha" //独立值,iota += 1
e //"ha" iota += 1
f = 100 //iota +=1
g //100 iota +=1
h = iota //7,恢复计数
i //8
)
*/
const a, b, c = 1, false, "str" //多重赋值
fmt.Println(a, b, c)
var n [10]int /* n 是一个长度为 10 的数组 */
var i,j int
/* 为数组 n 初始化元素 */
for i = 0; i < 10; i++ {
n[i] = i + 100 /* 设置元素为 i + 100 */
}
/* 输出每个数组元素的值 */
for j = 0; j < 10; j++ {
fmt.Printf("Element[%d] = %d\n", j, n[j] )
}
var ip *int /* 指向整型*/
var fp *float32 /* 指向浮点型 */
var intp int = 10
var floatp float32 = 32.0
ip = &intp
fp = &floatp
fmt.Printf("变量地址: %x:%x\n", ip,fp )
var ptr *int
if ptr != nil {
fmt.Printf("ptr 的值为 : %x\n", ptr )
}
/*
type Books struct {
title string
author string
subject string
book_id int
}
*/
var Book1 Books /* 声明 Book1 为 Books 类型 */
/* book 1 描述 */
Book1.title = "Go 语言"
Book1.author = "www.runoob.com"
Book1.subject = "Go 语言教程"
Book1.book_id = 6495407
/* 打印 Book1 信息 */
fmt.Printf( "Book 1 title : %s\n", Book1.title)
fmt.Printf( "Book 1 author : %s\n", Book1.author)
fmt.Printf( "Book 1 subject : %s\n", Book1.subject)
fmt.Printf( "Book 1 book_id : %d\n", Book1.book_id)
printBook(&Book1)
/*定义切片
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,
功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,
在追加时可能使切片的容量增大。
你可以声明一个未指定大小的数组来定义切片:
var identifier []type
定义数组是var balance [10] float32或者var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
也就是说数组,[]中括号里必须要有东西,那怕是省略号
切片不需要说明长度。
或使用make()函数来创建切片:
var slice1 []type = make([]type, len)
也可以简写为
slice1 := make([]type, len)
也可以指定容量,其中capacity为可选参数。
make([]T, length, capacity)
这里 len 是数组的长度并且也是切片的初始长度。
或者s :=[] int {1,2,3 }
*/
var balance = [...]int {1,2,3 }
fmt.Println(reflect.TypeOf(balance))
s :=[] int {1,2,3 }
fmt.Println(reflect.TypeOf(s))
s = balance[:]
int_s := append(s, 4)
fmt.Println(s,int_s)
//循环
//这是我们使用range去求一个slice的和。使用数组跟这个很类似
nums := []int{2, 3, 4}
sum := 0
for _, num := range nums {
sum += num
}
fmt.Println("sum:", sum)
//在数组上使用range将传入index和值两个变量。上面那个例子我们不需要使用该元素的序号,
// 所以我们使用空白符"_"省略了。有时侯我们确实需要知道它的索引。
for i, num := range nums {
if num == 3 {
fmt.Println("index:", i)
}
}
//range也可以用在map的键值对上。
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
fmt.Printf("%s -> %s\n", k, v)
}
//range也可以用来枚举Unicode字符串。第一个参数是字符的索引,第二个是字符(Unicode的值)本身。
for i, c := range "go" {
fmt.Println(i, c)
}
/*定义map
声明变量,默认 map 是 nil
var map_variable map[key_data_type]value_data_type
使用 make 函数
map_variable := make(map[key_data_type]value_data_type)
*/
var countryCapitalMap map[string]string
/* 创建集合 */
countryCapitalMap = make(map[string]string)
/* map 插入 key-value 对,各个国家对应的首都 */
countryCapitalMap["France"] = "Paris"
countryCapitalMap["Italy"] = "Rome"
countryCapitalMap["Japan"] = "Tokyo"
countryCapitalMap["India"] = "New Delhi"
/* 使用 key 输出 map 值 */
for country := range countryCapitalMap {
fmt.Println("Capital of",country,"is",countryCapitalMap[country])
}
/* 查看元素在集合中是否存在 */
captial, ok := countryCapitalMap["United States"]
/* 如果 ok 是 true, 则存在,否则不存在 */
if(ok){
fmt.Println("Capital of United States is", captial)
}else {
fmt.Println("Capital of United States is not present")
}
/* 删除Map元素 */
delete(countryCapitalMap,"France");
fmt.Println("Entry for France is deleted")
fmt.Println("删除元素后 map")
/* 打印 map */
for country := range countryCapitalMap {
fmt.Println("Capital of",country,"is",countryCapitalMap[country])
}
//异常处理
/*
error类型是一个接口类型,这是它的定义:
type error interface {
Error() string
}
*/
f, e := Sqrt(1)
fmt.Println(f,e==nil)
f, e = Sqrt(-1)
fmt.Println(f,e==nil)
}
/*
1.不想变量被修改。 如果你不想变量被函数和方法所修改,那么选择类型T。相反,如果想修改原始的变量,则选择*T
2.如果变量是一个大的struct或者数组,则副本的创建相对会影响性能,这个时候考虑使用*T,只创建新的指针,这个区别是巨大的
3.(不针对函数参数,只针对本地变量/局部变量)对于函数作用域内的参数,如果定义成T,Go编译器尽量将对象分配到栈上,
而*T很可能会分配到对象上,这对垃圾回收会有影响
*/
func printBook( book *Books ) {
fmt.Printf( "Book title : %s\n", book.title);
fmt.Printf( "Book author : %s\n", book.author);
fmt.Printf( "Book subject : %s\n", book.subject);
fmt.Printf( "Book book_id : %d\n", book.book_id);
}
func Sqrt(f float64) (float64, error) {
if f < 0 {
return 0, errors.New("math: square root of negative number")
}
//错误为空
return f*f,nil
}