這兩天迷上了SEO。真心看不起百度的競價排名,但作為一個商業網站,賺錢是一件無可厚非的事情。只做活雷鋒,沒有大金主是做不長的。做完功課后,發現百度和google的SEO策略又不相同,幾乎是無法通用。百度目前占據着國內搜索市場70%的市場份額,雖然不齒百度的齷齪之舉,但也只能沉下心來好好琢磨琢磨百度的SEO策略。以前沒有接觸過SEO,不懂這里面的水。這兩天着了迷想好好研究研究SEO,才發現原來內容是否原創,網頁類型(靜態/動態),關鍵字覆蓋率,robots是否滿足要求,外鏈質量,網站結構都會影響到最終的排名。當然這里說的都是明面上的技術操作,沒提那些個灰色產業。既然稱之為灰色產業了,沒有老司機帶着,也很難明白是怎么運作的。問了一些買過SEO優化的朋友得知,有的SEO優化立竿見影,基本一周后就能沖到前10位,但不續費后,馬上下來(肯定有貓膩,但外行人還就是看不懂)。有的SEO會承諾保持多長時間,結果可想而知,這個排名會逐漸逐漸下降。以前感覺寫代碼是個技術活,最近一段時間越來越發現,寫代碼真心是個簡單的活,這些個說不清道不明,又能掙錢的才是技術活。這幾天有時間了,再看看SEO,看能不能把自己的博客也沖到前10名去。
但在沖前十之前,先堅持把這個系列寫完了。
<朝鮮三胖哥> 那一節,聊了一嘴,從普通類型轉換到interface{}是隱式轉換。這節就說一下interface{}這個類型吧,要不總感覺內容少一塊。反正也是入門級的書,聊嘛不是聊呀。我准備寫完了以后,出一個視頻系列,那會就改叫<golang脫口秀>。如果你有好的段子,好的想法或者要推廣嘛東西,歡迎發郵件給我(ztao8607@gmail.com),現在有一個影視公司已經下定了,其他人抓緊哦。
Golang中的interface{}有兩層含義,一層是單純的interface{},可以理解成Java的Object基類。因此所有的數據類型都可以轉化成interface{}。另外一層含義,就是接口類。這個接口類和Java的接口類又幾乎差不多,都是只聲明一些方法,而不具體實現。其實第一層里面的interface{}可以理解成特殊的接口類,這個接口類里面沒有聲明任何方法。所以兩層含義可以統一成一個事物。
如果直接把Java里面的接口含義拿過來,這就沒有意思了,也就不用寫Golang里面的接口類了。Golang的接口和Java的接口說到底本質相同,但模樣千秋。下面來看Golang中如何聲明一個接口:
type interface_name interface {
method_name1 [return_type]
method_name2 [return_type]
method_name3 [return_type]
...
method_namen [return_type]
}
在聲明struct時候,是type name struct。這里聲明接口,是用type name interface,所以不用混淆了。在struct里面,都是各個成員屬性,而在interface里面,就都是各個成員函數。從這點來看,Golang和Java的interface聲明區別不大,大的區別在如何使用上面,Golang的使用要比Java靈活太多了。用事實來說話,看下面:
type Shape interface {
area() float64
}
func getArea(shape Shape) float64 {
return shape.area()
}
聲明了一個Shape的interface,里面有一個成員函數,是area,返回一個float64。而getArea只接受Shape接口類型。好,該上實現類了。
type Circle struct {
x,y,radius float64
}
func(circle Circle) area() float64 {
return math.Pi * circle.radius * circle.radius
}
現在Circle類就實現了剛才Shape的接口。不信,自己敲個代碼,驗證一下:
circle := Circle{x:0,y:0,radius:5}
fmt.Printf("Circle area: %f\n",getArea(circle))
嘿,一准兒能給你輸出結果。
如果只有一個實現類,那就體現不出接口的優勢了。再上一個實現類:
type Rectangle struct {
width, height float64
}
func(rect Rectangle) area() float64 {
return rect.width * rect.height
}
rectangle := Rectangle {width:10, height:5}
fmt.Printf("Rectangle area: %f\n",getArea(rectangle))
瞅瞅,又不一樣了吧。現在Rectangle和Circle都實現了Shape接口類。怎么實現的?如果你是從Java轉過來的,一定會默認去找extend關鍵字,瞅准了,上面可沒有extend關鍵字。
實現的秘密就在於Rectangle和Circle兩個類都有area() float64這個函數。所以在Golang當中,如何實現一個接口類?那就是把接口類中的函數都實現了,就成。
無論接口類中定義了幾個函數,都實現了。如果用不着,那就寫個函數聲明,里面加上空實現就可以。照這個邏輯,一個實現類理論上豈不是能實現無限個接口? 恩,是的,you are right!是這樣的!
如果一個項目中,代碼太多了,或者交接了好幾把手,等你分析代碼的時候,你都不知道這個類實現了多少個接口。正所謂有利有弊,Golang中接口的靈活性可以大大減少代碼量,減少耦合性。但也反過來降低了可讀性,舉個例子,如果程序出了bug,而這個bug恰恰出現在一個接口函數中,看代碼的時候,你都不知道是哪個實現類出的問題。別說使用go的debug工具,在線上很少會有通過debug打斷點進行調試的機會,一來線上環境這么容易進行debug,就說明太不安全了。理論上生產環境中的代碼都不應該包含debug信息。二來,有些問題只有在滿足一定條件,例如大流量,高並發,某些特殊請求下才能復現,貿然使用debug,已經破壞復現環境了,半天都找不到問題。所以建議在寫代碼的時候,一定要記得輸出日志,最好能在關鍵節點輸出盡可能的詳細日志。
Golang中的接口基本使用方法就是這些,如果你有Java基礎那么就沒有學習難度了。如果沒有,也沒關系,多寫幾個代碼也就差不多了。下面來看一下實際環境中經常使用到的接口:
type error interface {
Error() string
}
沒錯,是Error。在此之前,我們都沒有考慮如果代碼出錯了怎么辦?所以這個時候就補上這個漏洞。Golang沒有try.. catch.. finally。所有的錯誤都是通過error來處理的,經典的代碼如下:
err := xxxxxx
if err != nil {
....
}
基本就是這樣,再高逼格的,就是把err在封裝成各種類型。但基本都是這樣一套處理方式。Golang也允許自己創建error信息,比如:
func Sqrt(value float64)(float64, error) {
if(value < 0){
return 0, errors.New("Math: negative number passed to Sqrt")
}
return math.Sqrt(value)
}
用戶可以通過errors.New()來創建自帶業務邏輯的錯誤信息。這方面就不多展開了,因為每個team都有自己的編碼規范,對error的處理方式也千奇百怪,沒法統一說明。但處理模式就上面那一套,所以最后來一個實際代碼結束Error:
package main
import "errors"
import "fmt"
import "math"
func Sqrt(value float64)(float64, error) {
if(value < 0){
return 0, errors.New("Math: negative number passed to Sqrt")
}
return math.Sqrt(value), nil
}
func main() {
result, err:= Sqrt(-1)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(result)
}
result, err = Sqrt(9)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(result)
}
}
我的博客即將搬運同步至騰訊雲+社區,邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan