GoCN 每日新闻(2017-04-25)

回复

astaxie 发起了问题 • 3 人关注 • 0 个回复 • 1551 次浏览 • 2017-04-25 21:27 • 来自相关话题

和我一步步部署 kubernetes 集群

opsnull 发表了文章 • 5 个评论 • 2008 次浏览 • 2017-04-13 18:42 • 来自相关话题

Go之旅-for循环

frankphper 发表了文章 • 0 个评论 • 762 次浏览 • 2017-04-09 22:51 • 来自相关话题


package main

import (
"fmt"
)

// count函数
func count() int {
fmt.Println("count.") // 打印字符串用来查看count函数执行次数
return 3
}

// main函数
func main() {
// for循环
// 初始化表达式,支持函数调用或定义局部变量
for i := 0; i < 10; i++ {
fmt.Println(i)
}
// 类似while循环
i := 0
for i < 10 {
fmt.Println(i)
i++
}
// 类似无限循环
for {
break
}
// 初始化语句中的count函数仅执行一次
for i, c := 0, count(); i < c; i++ {
fmt.Println("a", i)
}

c := 0
// 条件表达式中的count函数重复执行
for c < count() {
fmt.Println("b", c)
c++
}
// 规避条件表达式中的count函数重复执行,在初始化表达式中定义局部变量保存count函数返回结果
count := count()
d := 0
for d < count {
fmt.Println("c", d)
d++
}
// goto定点跳转
// 须先定义标签,并且未用到的标签会引发编译错误
// 不能跳转到其它函数,或内层代码块内
for i := 0; i < 10; i++ {
fmt.Println(i)
if i > 5 {
goto exit
}
}
exit:
fmt.Println("exit.")

// break 用户switch、for、select语句,终止整个语句块执行。continue 仅用于for循环,终止后续逻辑,立即进入下一轮循环
for i := 0; i < 10; i++ {
if i%2 == 0 {
continue // 立即进入下一轮循环
}
if i > 5 {
break // 立即终止整个for循环
}
fmt.Println(i)
}
// 配合标签,break和continue可在多层嵌套中指定目标层级
outer:
for i := 0; i < 5; i++ {
for j := 0; j < 10; j++ {
if j > 2 {
fmt.Println()
continue outer
}

if i > 2 {
break outer
}
fmt.Print(i, ":", j, " ")
}
}

}
-->

在 Go 語言用一行程式碼自動化安裝且更新 Let’s Encrypt 憑證

appleboy 发表了文章 • 2 个评论 • 873 次浏览 • 2017-04-07 15:07 • 来自相关话题

聊天服务器玩具

elvin5 发表了文章 • 0 个评论 • 741 次浏览 • 2017-03-31 12:49 • 来自相关话题

如何实现一个Java Class字节解析器

tinylcy 发表了文章 • 6 个评论 • 807 次浏览 • 2017-03-28 20:21 • 来自相关话题

Go 語言的錯誤訊息處理

appleboy 发表了文章 • 1 个评论 • 592 次浏览 • 2017-03-25 15:12 • 来自相关话题


Go 輸出錯誤訊息


在 Go 語言內有兩種方式讓函示 (function) 可以回傳錯誤訊息,一種是透過 errors 套件或 fmt 套件,先看看 errors 套件使用方式:


package main

import (
"errors"
"fmt"
)

func isEnable(enable bool) (bool, error) {
if enable {
return false, errors.New("You can't enable this setting")
}

return true, nil
}

func main() {
if _, err := isEnable(true); err != nil {
fmt.Println(err.Error())
}
}

請先引入 errors 套件,接著透過 errors.New("message here"),就可以實現 error 錯誤訊息。接著我們打開 errors package 原始碼來看看


package errors

// New returns an error that formats as the given text.
func New(text string) error {
return &errorString{text}
}

// errorString is a trivial implementation of error.
type errorString struct {
s string
}

func (e *errorString) Error() string {
return e.s
}

可以發現 errors 套件內提供了 New 函示,讓開發者可以直接建立 error 物件,並且實現了 error interface。在 Go 語言有定義 error interface 為:


type error interface {
Error() string
}

只要任何 stuct 有實作 Error() 接口,就可以變成 error 物件。這在下面的自訂錯誤訊息會在提到。除了上面使用 errors 套件外,還可以使用 fmt 套件,將上述程式碼改成:


func isEnable(enable bool) (bool, error) {
if enable {
return false, fmt.Errorf("You can't enable this setting")
}

return true, nil
}

這樣也可以成功輸出錯誤訊息,請深入看 fmt.Errorf


// Errorf formats according to a format specifier and returns the string
// as a value that satisfies error.
func Errorf(format string, a ...interface{}) error {
return errors.New(Sprintf(format, a...))
}

你可以發現在 fmt 套件內,引用了 errors 套件,所以基本上本質是一樣的。


Go 錯誤訊息測試


在 Go 語言如何測試錯誤訊息,直接引用 testing 套件


package error

import "testing"

func TestIsMyError(t *testing.T) {
ok, err := isEnable(true)

if ok {
t.Fatal("should be false")
}

if err.Error() != "You can't enable this setting" {
t.Fatal("message error")
}
}

另外 Go 語言最常用的測試套件 Testify,可以改寫如下:


package error

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestIsEnable(t *testing.T) {
ok, err := isEnable(true)
assert.False(t, ok)
assert.NotNil(t, err)
assert.Equal(t, "You can't enable this setting", err.Error())
}

Go 自訂錯誤訊息


從上面的例子可以看到,錯誤訊息都是固定的,如果我們要動態改動錯誤訊息,就必須帶變數進去。底下我們來看看如何實現自訂錯誤訊息:


package main

import (
"fmt"
)

// MyError is an error implementation that includes a time and message.
type MyError struct {
Title string
Message string
}

func (e MyError) Error() string {
return fmt.Sprintf("%v: %v", e.Title, e.Message)
}

func main() {
err := MyError{"Error Title 1", "Error Message 1"}
fmt.Println(err)

err = MyError{
Title: "Error Title 2",
Message: "Error Message 2",
}
fmt.Println(err)
}

也可以把錯誤訊息包成 Package 方式


package error

import (
"fmt"
)

// MyError is an error implementation that includes a time and message.
type MyError struct {
Title string
Message string
}

func (e MyError) Error() string {
return fmt.Sprintf("%v: %v", e.Title, e.Message)
}

main.go 就可以直接引用 error 套件


package main

import (
"fmt"

my "github.com/go-training/training/example04/error"
)

func main() {
err := my.MyError{"Error Title 1", "Error Message 1"}
fmt.Println(err)

err = my.MyError{
Title: "Error Title 2",
Message: "Error Message 2",
}
fmt.Println(err)
}

如何測試錯誤訊息是我們自己所定義的呢?請在 error 套件內加入底下測試函示


func IsMyError(err error) bool {
_, ok := err.(MyError)
return ok
}

由於我們實作了 error 接口,只要是 Interface 就可以透過 Type assertion 來判斷此錯誤訊息是否為 MyError


package error

import "testing"

func TestIsMyError(t *testing.T) {
err := MyError{"title", "message"}

ok := IsMyError(err)

if !ok {
t.Fatal("error is not MyError")
}

if err.Error() != "title: message" {
t.Fatal("message error")
}
}

這樣在專案裡就可以實現多個錯誤訊息,寫測試時就可以直接判斷錯誤訊息為哪一種自訂格式。


結論


在 Go 裡面寫錯誤訊息真的很方便又很容易,動態訊息請自定,反之,固定訊息請直接宣告 const 就可以了。在寫套件給大家使用時,大部份都是使用固定訊息,如果是大型專案牽扯到資料庫時,通常會用動態自訂錯誤訊息比較多。


上述程式碼請參考這裡

-->

beego1.8版本功能征集

lkhjlbh 回复了问题 • 22 人关注 • 26 个回复 • 6149 次浏览 • 2017-03-22 17:58 • 来自相关话题

orm初探

elvin5 发表了文章 • 0 个评论 • 643 次浏览 • 2017-03-20 11:52 • 来自相关话题

Go之旅-Switch

frankphper 发表了文章 • 0 个评论 • 704 次浏览 • 2017-03-15 22:51 • 来自相关话题

第三届GopherChina大会正式启动了

hector 回复了问题 • 16 人关注 • 14 个回复 • 2630 次浏览 • 2017-03-13 15:03 • 来自相关话题

Go之旅-常量

frankphper 发表了文章 • 2 个评论 • 560 次浏览 • 2017-03-12 16:42 • 来自相关话题

求推荐或分享go并发编程方面的资源。谢谢

yang11 回复了问题 • 6 人关注 • 2 个回复 • 1363 次浏览 • 2017-03-09 21:34 • 来自相关话题

使用 Elastic Stack 来监控和调优 Golang 应用程序

astaxie 发表了文章 • 1 个评论 • 2784 次浏览 • 2017-03-05 14:36 • 来自相关话题

五大最前沿的实战主题,与技术大咖面对面,2017 Gopher China 上海站来了!

astaxie 发表了文章 • 1 个评论 • 886 次浏览 • 2017-03-04 22:29 • 来自相关话题