公司网站百度搜不到,网站建设具体建设流程,做社区网站怎么做,网站建设的类型或分类1.流程控制
1.1 条件语句
if a 5 { return 0
} else { return 1
}
注意#xff1a;在有返回值的函数中#xff0c;不允许将“最终的”return语句包含在if...else...结构中#xff0c; 否则会编译失败#xff01;#xff01;#xff01;
func example(x int) i…1.流程控制
1.1 条件语句
if a 5 { return 0
} else { return 1
}
注意在有返回值的函数中不允许将“最终的”return语句包含在if...else...结构中 否则会编译失败
func example(x int) int { if x 0 { return 5 } else { return x }
}// 编译失败的原因Go编译器无法找到终止该函数的return语句
1.2 选择语句
switch i { case 0: fmt.Printf(0) case 1: fmt.Printf(1) case 2: fallthrough case 3: fmt.Printf(3) case 4, 5, 6: fmt.Printf(4, 5, 6) default: fmt.Printf(Default)
} 运行上面的案例将会得到如下结果 i 0 时输出 0 i 1 时输出 1 i 2 时输出 3 i 3 时输出 3 i 4 时输出 4, 5, 6 i 5 时输出 4, 5, 6 i 6 时输出 4, 5, 6 i 其他任意值时输出 Default 。 比较有意思的是switch后面的表达式甚至不是必需的比如下面的例子
switch { case 0 Num Num 3: fmt.Printf(0-3) case 4 Num Num 6: fmt.Printf(4-6) case 7 Num Num 9: fmt.Printf(7-9)
}
只有在case中明确添加fallthrough关键字才会继续执行紧跟的下一个case可以不设定switch之后的条件表达式在此种情况下整个switch结构与多个 if...else...的逻辑作用等同
1.3 循环语句 在条件表达式中也支持多重赋值 func ForCase() {sum : 0for i : 0; i 10; i {sum i}fmt.Println(sum) // 45// 在条件表达式中也支持多重赋值如下表示a : []int{1, 2, 3, 4, 5, 6}for i, j : 0, len(a)-1; i j; i, j i1, j-1 {a[i], a[j] a[j], a[i]}fmt.Println(a) // [6 5 4 3 2 1]
} 另外,Go语言的for循环同样支持continue和break来控制循环但是它提供了一个更加高级的break可以选择中断哪一个循环如下例子 for j : 0; j 5; j { for i : 0; i 10; i { if i 5 { break JLoop } fmt.Println(i) }
}
JLoop: 本例中 break 语句终止的是 JLoop 标签处的外层循环。 2.函数 在Go中函数的基本组成为关键字func、函数名、参数列表、返回值、函数体和返回语句 2.1函数定义 用一个最简单的加法函数来进行详细说明 package mainimport (fmt
)
import errorsfunc Add(a int, b int) (ret int, err error) {if a 0 || b 0 { // 假设这个函数只支持两个非负数字的加法err errors.New(Should be non-negative numbers!)return}return a b, nil // 支持多重返回值
}func main() {res, err : _case.Add(1, 2)if err ! nil {return}fmt.Println(res)
} 如果参数列表中若干个相邻的参数类型的相同比如上面例子中的 a 和 b 则可以在参数列表中省略前面变量的类型声明如下所示 func Add(a, b int)(ret int, err error) { // ...
} 如果返回值列表中多个返回值的类型相同也可以用同样的方式合并。 如果函数只有一个返回值也可以这么写 func Add(a, b int) int { // ...
} 2.2 函数调用 函数调用非常方便只要事先导入了该函数所在的包就可以直接按照如下所示的方式调用函数 import mymath// 假设Add被放在一个叫mymath的包中// ...
c : mymath.Add(1, 2) 先牢记这样的规则 小写字母开头的函数只在本包内可见大写字母开头的函数才能被其他包使用这个规则也适用于类型和变量的可见性 2.3 不定参数 1不定参数类型 不定参数 指函数传入的参数个数为不定数量 首先需要将函数定义为接受不定参数类型 func myfunc(args ...int) { for _, arg : range args { fmt.Println(arg) }
}// 这段代码的意思是函数myfunc()接受不定数量的参数这些参数的类型全部是int
// 所以它可以用如下方式调用myfunc(2, 3, 4)
myfunc(1, 3, 7, 13) 形如...type格式的类型只能作为函数的参数类型存在并且必须是最后一个参数 它是一 个语法糖syntactic sugar即这种语法对语言的功能并没有影响但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性从而减少程序出错的机会。 从内部实现机理来说说类型...type本质上是一个数组切片也就是[]type这也是为什么上面的参数args可以用for循环来获得每个传入的参数 假如没有...type这样的语法糖开发者将不得不这么写
func myfunc2(args []int) { for _, arg : range args { fmt.Println(arg) }
} 从函数的实现角度来看这没有任何影响该怎么写就怎么写。但从调用方来说情形则完 全不同 myfunc2([]int{1, 3, 7, 13}) 们不得不加上 []int{} 来构造一个数组切片实例。但是有了 ...type这个语法糖我们就不用自己来处理了。 2不定参数的传递 package mainimport (fmt
)func processFunc(args ...int) {for i, _ : range args {args[i] 1}fmt.Println(args)
}func myfunc(args ...int) {// 按照原样传递processFunc(args...)// 传递片段实际上任意的int slice都可以传进去processFunc(args[1:]...)
}func main() {myfunc(2, 3, 4)
}3任意类型的不定参数 之前的例子中将不定参数类型约束为 int 如果你希望传任意类型可以指定类型为 interface{}。下面是 Go 语言标准库中 fmt.Printf() 的函数原型 func Printf(format string, args ...interface{}) { // ...
} 用interface{}传递任意类型数据是Go语言的惯例用法。使用interface{}仍然是类型安全的和C/C不太一样 func MyPrintf(args ...interface{}) {for _, arg : range args {switch arg.(type) {case int:fmt.Println(arg, is an int value.)case string:fmt.Println(arg, is a string value.)case int64:fmt.Println(arg, is an int64 value.)default:fmt.Println(arg, is an unknown type.)}}
}func main() {var v1 int 1var v2 int64 234var v3 string hehedavar v4 float32 1.234_case.MyPrintf(v1, v2, v3, v4)
} 4多返回值 与C、C和Java等开发语言的一个极大不同在于Go语言的函数或者成员的方法可以有多个返回值这个特性能够让我们写出比其他语言更优雅更简洁的代码。 比如File.Read()函数就可以同时返回读取的字节数和错误信息 如果读取文件成功则返回值中的n为读取的字节数err为nil否则err为具体的出错信息 func (file *File) Read(b []byte) (n int, err Error) 同样从上面的方法原型可以看到我们还可以给返回值命名就像函数的输入参数一样。 返回值被命名之后它们的值在函数开始的时候被自动初始化为空在函数中执行不带任何参数的return语句时会返回对应的返回值变量的值 Go语言并不需要强制命名返回值但是命名后的返回值可以让代码更清晰可读性更强同时也可用于文档 如果调用方调用了一个具有多返回值的方法但是却不想关心其中的某个返回值可以简单地用一个下划线_来跳过这个返回值比如下面的代码表示调用者在读文件的时候不想关心Read()函数返回的错误码 n, _ : f.Read(buf) 5匿名函数与闭包 ① 匿名函数是指不需要定义函数名的一种函数实现方式匿名函数由一个不带函数名的函数声明和函数体组成如下所示 func NMFunc() {f : func(x, y int) int {return x y}fmt.Println(f(1, 2)) // 输出: 3// 创建一个通道replyChan : make(chan int)// 启动一个新的 Goroutine执行匿名函数并向通道发送数据go func(ch chan int) {ch - 42}(replyChan) // 花括号后直接跟参数列表表示调用// 从通道接收数据ack : -replyChan// 打印接收到的数据fmt.Println(ack) // 输出: 42// 关闭通道close(replyChan)
}②闭包Go的匿名函数是一个闭包 基本概念闭包是可以包含自由未绑定到特定对象变量的代码块这些变量不在这个代码块内或者任何全局上下文中定义而是在定义代码块的环境中定义。要执行的代码块由于自由变量包含 在代码块中所以这些自由变量以及它们引用的对象没有被释放为自由变量提供绑定的计算环境作用域。 闭包的价值在于可以作为函数对象或者匿名函数 Go语言中的闭包Go语言中的闭包同样会引用到函数外的变量闭包的实现确保只要闭包还被使用那么被闭包引用的变量会一直存在 closure.go package main
import ( fmt
)
func main() { var j int 5 a : func()(func()) { var i int 10 return func() { fmt.Printf(i, j: %d, %d\n, i, j) } }() a() j * 2 a()
} 上述例子的执行结果是 上述例子的执行结果是 i, j: 10, 5 i, j: 10, 10 在上面的例子中变量a指向 的闭包函数引用了局部变量 i 和 j i的值被隔离在闭包外不能被修改改变j的值以后再次调用a发现结果是修改过的值。 2.4 错误处理 漂亮的错误处理规范是 Go 语言最大的亮点之一 1error接口 Go语言引入了一个关于错误处理的标准模式即error接口该接口的定义 type error interface { Error() string
} 对于大多数函数如果要返回错误大致上都可以定义为如下模式将 error 作为多种返回 值中的最后一个但这并非是强制要求 func Foo(param int)(n int, err error) { // ...
} 调用时的代码建议按如下方式处理错误情况: n, err : Foo(0)
if err ! nil { // 错误处理
} else { // 使用返回值n
} 自定义的error类型 步骤一定义一个用于承载错误信息的类型 func (e *PathError) Error() string { return e.Op e.Path : e.Err.Error()
} 当然这里是一个完整的例子展示了如何定义一个自定义的 PathError 类型并在文件操作中使用这个类型在出错时进行错误处理和信息提取 package mainimport (fmtos
)// PathError 自定义错误类型
type PathError struct {Op stringPath stringErr error
}// 实现 error 接口的 Error 方法
func (e *PathError) Error() string {return e.Op e.Path : e.Err.Error()
}// 函数用来模拟文件操作并返回一个自定义的 PathError 错误
func simulateFileOperation() error {// 尝试获取文件信息这里故意对一个不存在的文件操作_, err : os.Stat(a.txt)if err ! nil {// 返回自定义的 PathError 错误return PathError{Op: stat,Path: a.txt,Err: err,}}return nil
}func main() {// 调用模拟文件操作的函数err : simulateFileOperation()if err ! nil {// 把错误断言为 *PathError 类型if e, ok : err.(*PathError); ok e.Err ! nil {// 获取 PathError 类型变量 e 中的其他信息并处理fmt.Printf(Operation: %s\n, e.Op)fmt.Printf(Path: %s\n, e.Path)fmt.Printf(Error: %s\n, e.Err)fmt.Printf(Full Error: %s\n, e.Error())} else {// 其他类型的错误fmt.Println(err)}} else {// 文件操作成功fmt.Println(File operation succeeded)}
} 在这个示例中 ① 定义了一个PathError类型这个类型有Op操作、Path路径和Err底层错误三个字段 ② 实现了PathError类型的Error方法以满足error接口 ③ 编写了一个simulateFileOperation函数这个函数尝试获取一个不存在的文件的状态并返回一个自定义的PathError错误 ④ 在main函数中调用simulateFileOperation函数接收并处理这个自定义错误 这样当你运行这个示例时如果文件a.txt不存在会输出 Operation: stat
Path: a.txt
Error: stat a.txt: no such file or directory
Full Error: stat a.txt: stat a.txt: no such file or directory 这个示例展示了如何自定义错误类型并在程序中使用它来进行错误处理和信息提取 这就是Go中error类型的使用方法与其他语言中的异常相比Go的处理相对比较直观简单 2.5 defer 关键字defer是Go语言引入的一个非常有意思的特性