Go 1.27 升了一波,泛型方法和 JSON v2 真香但有个坑
Go 1.27 åäºä¸æ³¢ï¼æ³åæ¹æ³å JSON v2 çé¦ä½æä¸ªå
Flynt 2026-08-20 0 é 读9å鿍天ä¸åå·å° Go 宿¹åå®¢æ´æ°äºï¼1.27 æ£å¼åå¸ã ææä¸æä¸ªè·äºä¸¤å¹´çå端æå¡ï¼ç¨ç Go 1.25ï¼ä¸ç´æ²¡å¨è¿ãçå° changelog åç "generic methods" å "encoding/json/v2"ï¼å¿æ³è¿ä¿©è¦æ¯è½ç¨ä¸ï¼ä»£ç è½ç²¾ç®ä¸å°ãè¶çè¿ä¸¤å¤©æ²¡ä»ä¹ç´§æ¥éæ±ï¼æäºä¸ªåæ¯å¼å§åã æ´ä¸ªè¿ç¨æ¯é¢æ³ç顺å©ï¼ä½ json v2 é£è¾¹è¿æ¯è¸©äºä¸ªå°åï¼è®°å½ä¸ä¸ã
æ³åæ¹æ³ï¼ç»äºä¸ç¨å¨å 级å«å"ä¸è½å½æ°"äº
è¿ä¸ªå忝æå级çæå¤§å¨åã ä¹å Go çæ³ååªè½å¨å 级å«å£°æå½æ°ï¼ä¸è½ç»ç±»åå æ³åæ¹æ³ãå¬èµ·æ¥æ¯ä¸ªå°éå¶ï¼ä½å®é åèµ·æ¥å¾æ¶å¿ãæ¿æé¡¹ç®éä¸ä¸ª Result ç±»å举ä¾ââå°è£ æ¥å£è¿åå¼çï¼éè¦æå 鍿°æ®è½¬æä¸åç±»åï¼
// Go 1.26 å以åï¼æ¯ç§ç±»åé½è¦åä¸ä¸ªæ¹æ³
func (r *Result[T]) ToString() (string, error) { ... }
func (r *Result[T]) ToInt() (int, error) { ... }
func (r *Result[T]) ToFloat() (float64, error) { ... }
è¿è¿åªæ¯ä¸ç§ãå¦æä½ è¦æ¯ææ´å¤ç±»åââæ¯å¦ ToBoolãToTimeãToDurationââå°±å¾ä¸åå°å æ¹æ³ã宿¹ math/rand/v2 ç Rand ç±»åå°±æ¯è¿ä¸ªçç¹ï¼ä¹å Int32NãInt64NãIntN ååäºä¸ä¸ªï¼ä¸é使²¡åæ³ã
Go 1.27 ç´æ¥æ¯æå¨æ¹æ³ä¸å£°æç±»ååæ°äºï¼
// Go 1.27ï¼ä¸ä¸ªæ³åæ¹æ³æå®æææ´æ°ç±»å
func (r *Rand) N[Int intType](n Int) Int
æé©¬ä¸æé¡¹ç®éç Result æ¹æäºè¿æ ·ï¼
type Convertible interface {
string | int | int64 | float64 | bool
}
func (r *Result[T]) As[V Convertible]() (V, error) {
var zero V
switch v := any(r.data).(type) {
case string:
if target, ok := any(zero).(string); ok {
_ = target
return any(v).(V), nil
}
case int:
if target, ok := any(zero).(int); ok {
_ = target
return any(v).(V), nil
}
case int64:
if target, ok := any(zero).(int64); ok {
_ = target
return any(v).(V), nil
}
case float64:
if target, ok := any(zero).(float64); ok {
_ = target
return any(v).(V), nil
}
}
return zero, fmt.Errorf("unsupported conversion: %T", r.data)
}
è°ç¨ä¾§çååæ´ææ¾ã以忝ï¼
val, err := result.ToString()
num, err := result.ToInt()
fl, err := result.ToFloat()
ç°å¨æ¯ï¼
val, err := result.As[string]()
num, err := result.As[int]()
fl, err := result.As[float64]()
ä¸ä¸ªæ¹æ³åï¼ç±»å忰驱å¨ã代ç éç´æ¥ç äºä¸åå¤ï¼èä¸ä»¥åå æ°ç±»ååªéè¦å¨ constraint é追å ä¸ä¸ªç±»åå°±è¡ï¼ä¸ç¨åå䏿´ä¸ªæ¹æ³ã
è¿ä¸ªæ¹å¨çå®é
æ¶çæ¯æé¢æ³çè¿å¤§ãå 为以å为äºå°åå ä¸ªæ¹æ³ï¼æåäºä¸ªåå·§ç设计ââç¨ä¸ä¸ª map[string]func() (interface{}, error) æ¥ååç±»åç转æ¢å½æ°ï¼è¿è¡æ¶æ¥è¡¨è°ç¨ã代ç å¾ä¸ä½ç¡®å®çäºä¸å°éå¤ä»£ç ãæäºæ³åæ¹æ³ä¹åï¼ææé£ä¸ª map æ´æ®µå äºï¼æ¹åç±»åå®å
¨çæ¹å¼ï¼ä»£ç åèæ´å¹²åã
ä¸è¿æä¸ªå°æ¹è¦æ³¨æï¼æ³åæ¹æ³ä¸è½å®ç°æ¥å£æ¹æ³ãè¿ä¸ªéå¶å®æ¹ææ¡£åå¾å¾æ¸ æ¥ï¼ä½å¦æä½ ä¹å设计äºä¸å¥"æ³å彿° + æ¥å£"çç»å模å¼ï¼å级åå¯è½è¦éæ°æ³ä¸ä¸æ½è±¡æ¹å¼ãæçåæ³æ¯æåæ¥é æ¥å£çº¦æçé¨åæå°è°ç¨ä¾§ï¼æ³åæ¹æ³åªè´è´£åä¸ç±»å转æ¢ï¼åèæ´æ¸ æ°äºã å¦å¤å½æ°ç±»åæ¨æä¹ææ¹è¿ãä¹åæ³å彿°èµå¼ç»å½æ°ç±»ååéçæ¶åï¼å¿ é¡»æ¾å¼åç±»ååæ°ï¼ç°å¨ä¸ç¨äºï¼
func Transform[T any](v T) string {
return fmt.Sprintf("%v", v)
}
type IntToStr func(int) string
// Go 1.26ï¼éè¦æ¾å¼å Transform[int]
// Go 1.27ï¼èªå¨æ¨æ T = int
var fn IntToStr = Transform
è¿ä¸ªå°æ¹è¿å¨å®é 项ç®éå½±åä¸å¤§ï¼ä½è½çæä¸å°åä½çç±»åæ æ³¨ã å¦å¤ç»æä½åé¢éåå§åä¹é¡ºææ¹è¿äºãåµå¥ç»æä½çåæ®µå¯ä»¥ç´æ¥åï¼
type Config struct {
DB struct {
Host string
Port int
}
}
// Go 1.27ï¼ç´æ¥ååæ®µå
c := Config{
Host: "localhost", // ä¸ç¨å DB.Host
Port: 5432,
}
è¿ä¸ªæ¹å¨çåç颿²¡æ³åæ¹æ³å¤§ï¼ä½åèµ·æ¥ç¡®å®èæäºç¹ã
json/v2ï¼æ§è½æåæ¯ççï¼ä½ä¸¥æ ¼æ¨¡å¼ä¼ç¸
è¿æ¯è¿æ¬¡å级éæ"æä¸åå"çé¨åã
Go 1.27 æ°å¢äº encoding/json/v2 å
ååºå±ç encoding/json/jsontextãv2 çæ ¸å¿æ¹è¿æ¯ï¼å¯ä»¥é
ç½®è¡ä¸ºé项ï¼é»è®¤æç»æ æ UTF-8 åéå¤ç JSON keyã
ä½å
³é®ä¸æ¯ v2 æ¬èº«ââèæ¯èç encoding/json åºå±å·²ç»åæ¢å° v2 å®ç°äºãä¹å°±æ¯è¯´ï¼ä½ å级 Go çæ¬ä¹åï¼å³ä½¿ä»£ç ä¸è¡ä¸æ¹ï¼json.Unmarshal ä¹ä¼åå¿«ã宿¹è¯´ unmarshal æ§è½æå¯æç¥çæåï¼æè·äºä¸é¡¹ç®éç benchmarkï¼ç¡®å®å¿«äº 15% å·¦å³ï¼ä¸»è¦åçå¨å¤§éå°å¯¹è±¡çååºåååºæ¯ã
å°è¿éä¸å顺å©ï¼å¿æ³è¿æ¬¡å级ä¹å¤ªä¸æ»äºãç¶åæè·äºéææµè¯ã
æäºã
ä¸å¼å§è¿ä»¥ä¸ºæ¯å«çæ¹å¨å¼èµ·çï¼debug äºä¸åæåç°æ¯ json è§£ææ¥éãåå æ¯ä¸ä¸ªå¯¹æ¥ç¬¬ä¸æ¹ç³»ç»çæ¥å£ï¼å¯¹æ¹è¿åç JSON éæéå¤ç keyãå¤§æ¦æ¯è¿æ ·ç payloadï¼
{
"status": "ok",
"data": {"value": 100},
"data": {"extra": true}
}
ä¹åç encoding/json ä¼éé»åæåä¸ä¸ªå¼ï¼ç¨åºç
§å¸¸è·ãv2 çä¸¥æ ¼æ¨¡å¼ç´æ¥æ¥éï¼duplicate name "data"ã
è¿å
¶å®æ¯æ£ç¡®è¡ä¸ºââRFC 8259 é说äºï¼éå¤ key å±äº"ä¸è§èä½ä¸åºæ¥é"çç°è²å°å¸¦ï¼åå®ç°å¤çæ¹å¼ä¸åãä½ä½ æ¶ä¸ä½ç°å®ä¸çéå°±æ¯ææå¡å¨åè¿ç§ payloadã
å¤çæ¹å¼æä¸¤ç§ãå¦æä½ ç´æ¥ç¨ encoding/json/v2ï¼å¯ä»¥å¨è°ç¨æ¶ä¼ é项å
³éä¸¥æ ¼æ£æ¥ï¼
import "encoding/json/v2"
// å
许éå¤ keyï¼å
¼å®¹æ§è¡ä¸ºï¼
err := json.Unmarshal(data, &target, json.WithRejectDuplicateFieldName(false))
妿æ¯èç encoding/json å
ï¼å®å¨ä¿æ v1 è¯ä¹çåæ¶åºå±èµ°äº v2 å®ç°ï¼è¡ä¸ºä¸åãä¹å°±æ¯è¯´ï¼å¦æä½ 没æä¸»å¨åæ¢å° v2 å
ç APIï¼è代ç çè¡ä¸ºæ¯å
¼å®¹çã
æçæ
嵿¯å 为ä¹å卿å¤éææ¶å¼å
¥äº v2 ç MarshalWrite æ¥ä¼å大 payload çåºååï¼é£è¾¹ä¹åå½±åãæåç»ä¸å äº WithRejectDuplicateFieldName(false) éé¡¹ï¼æµè¯å
¨è¿ã
ä¸è¿è¯è¯´åæ¥ï¼å¦æä½ ç项ç®é没æè¿ç§"è JSON"ï¼v2 çä¸¥æ ¼æ¨¡å¼åèæ¯å¥½äºãå®è½å¸®ä½ æååç°æ°æ®éçç»ææ§é®é¢ã建议æ°é¡¹ç®ç´æ¥ç¨ v2ï¼è项ç®å级åå è·ä¸éæµè¯ççææ²¡ææ¥éï¼æå°±å éé¡¹å ¼å®¹ã
uuid è¿æ ååºï¼å¯ä»¥ç æä¸ä¸ªä¾èµäº
è¿ä¸ªå忝è¾å°ä½å®ç¨ã以å项ç®éåºæ¬é½ä¼å¼ä¸ä¸ª github.com/google/uuidï¼å°±ä¸ºäºçæä¸ªè¯·æ± ID æè
订åå·ãç°å¨æ ååºç´æ¥æä¾äº uuid å
ï¼
import "uuid"
id := uuid.New() // çæ UUID v4
fmt.Println(id.String()) // "550e8400-e29b-41d4-a716-446655440000"
// è§£æ
parsed, err := uuid.Parse("550e8400-e29b-41d4-a716-446655440000")
// å®é
åºæ¯ï¼çæè¯·æ± ID åå
¥æ¥å¿
requestID := uuid.New()
log.Printf("request %s started, method=%s path=%s", requestID, r.Method, r.URL.Path)
æç´æ¥æé¡¹ç®éç github.com/google/uuid æ¢æäºæ ååºç uuidï¼go mod tidy ä¹åä¾èµå表干åäºä¸å°ãAPI åºæ¬å
¼å®¹ï¼æ¿æ¢ææ¬å¾ä½ï¼å°±æ¯å
¨å±æä¸ä¸ uuid. ç¶åæ¹ import è·¯å¾çäºã
å¯ä¸æ³¨æçæ¯ï¼æ ååºç uuid å
å½åç©ºé´æ¯é¡¶å±ç uuidï¼ä¸æ¯ stduuid ä¹ç±»çãå¦æä½ é¡¹ç®éå·²ç»æèªå®ä¹ç uuid å
æè
åéåï¼å¯è½ä¼å²çªã
goroutine æ³æ¼æ£æµç»äºæ£å¼å¯ç¨äº
è¿ä¸ªä¸æ¯è¯è¨å±é¢çååï¼ä½å¯¹ææ¥çº¿ä¸é®é¢å¸®å©å¾å¤§ã
goroutineleak profile å¨ Go 1.26 æ¯å®éªæ§çï¼1.27 æ£å¼ GA äºãå®è½èªå¨æ£æµé£äºæ°¸ä¹
é»å¡å¨ channelãmutexãcond ä¸ç goroutineã
ç¨æ³å¾ç®åï¼å¨ runtime/pprof éç´æ¥æ¿ï¼
import (
"net/http"
_ "net/http/pprof"
)
func main() {
// å¯å¨ pprof HTTP æ¥å£
go func() {
http.ListenAndServe("localhost:6060", nil)
}()
// ä½ çä¸å¡é»è¾...
}
ç¶åè®¿é® http://localhost:6060/debug/pprof/goroutineleakï¼å°±è½çå°æ³æ¼ç goroutine ä¿¡æ¯ãä¹åææ¥è¿ç§é®é¢åªè½é pprof goroutine æå¨æ° goroutine æ°éï¼å对ç
§ä»£ç æ¾åªéå¯è½é»å¡äºï¼æçå¾ä½ãç°å¨å·¥å
·ç´æ¥åè¯ä½ åªäº goroutine æ¯"æ»äºä½æ²¡è¢«åæ¶"çã
æå¨æµè¯ç¯å¢å¼äºå天ï¼ç¡®å®æå°äºä¸¤ä¸ªä»¥å没åç°çæ³æ¼ââä¸ä¸ªæ¯é误å¤çè·¯å¾éå¿è®° close channelï¼å¦ä¸ä¸ªæ¯ context åæ¶å worker goroutine æ²¡ææ£æ¥ ctx.Done()ï¼ä¸ç´å¨ range ä¸ä¸ªæ°¸è¿ä¸ä¼å ³éç channelã
è¿ä¸¤ä¸ªé®é¢é½æ¯å°é®é¢ï¼å个 goroutine å ä¸äºå¤å°å åã使们çæå¡è·äºå å¨ä¹åï¼æ³æ¼ç goroutine æ°éå·²ç»ç´¯ç§¯å°å¥½å åäºï¼è½ç¶è¿æ²¡å° OOM çç¨åº¦ï¼ä½ pprof éç goroutine æ°éæ²çº¿ä¸ç´å¨ç¬ï¼ççå¿éä¸è¸å®ãç°å¨æäºè¿ä¸ªå·¥å ·ï¼è³å°è½å®ææ«ä¸ä¸ï¼ä¸ç¨çå°çº¿ä¸åºé®é¢å廿æ¥ã
å ¶ä»é¡ºææä¸å´
å级è¿ç¨æ¬èº«æ²¡ä»ä¹æ³¢æï¼go install æ°çæ¬ä¹å go build 䏿è¿ï¼è¿ golang.org/x/exp éä¹åç¨çå 个æ³åè¾
å©å½æ°é½ä¸éè¦æå¨æ¹äºââå 为 1.27 æå®ä»¬æ¶è¿äºæ ååºãä¸é¢å 个å°ååä¹å¼å¾çæï¼
- å ååé ä¼åï¼å°äº 80 åèç对象åé ææ¬éäº 30%ãæç项ç®è·äºä¸åºåæµè¯ï¼æ´ä½ååæåäºä¸å° 1%ï¼ç¬¦å宿¹è¯´ç"real-world allocation-heavy programs ~1%"ãæç¥ä¸ææ¾ï¼ä½å±äºç½å«çæ§è½ã
- go doc æ¯æ
package@versionï¼ç»äºä¸ç¨åå° godoc.org 廿¥ç¹å®çæ¬çææ¡£äºï¼ç»ç«¯égo doc example.com/pkg@v1.2.3ç´æ¥çã - go mod tidy èªå¨åå¹¶ require åï¼ä¹å go.mod éæå¥½å 个 require åçå¯ä»¥èªå¨æ´çäºï¼å¼ºè¿«çç¦é³ã
- crypto/mldsaï¼åéåç¾å ML-DSAï¼FIPS 204ï¼è¿æ ååºäºãè·æçé¡¹ç®æ²¡å ³ç³»ï¼ä½åå®å ¨ç¸å ³çåå¦å¯ä»¥å ³æ³¨ã
- macOS è¦æ±æå° 13+ ï¼è¿å¨ç¨ macOS 12 çéè¦æ³¨æï¼Go 1.27 䏿¯æäºã
æ´ä½æ¥è¯´ï¼Go 1.27 æ¯ä¸ªå¼å¾åççæ¬ãæ³åæ¹æ³æ¯çäºä¸¤å¹´ç大æ¹è¿ï¼json/v2 çåºå±æ¿æ¢è®©è项ç®ä¸æ¹å¨ä¹è½åæ§è½çº¢å©ï¼uuid è¿æ ååºåäºä¸ªä¾èµãå级è¿ç¨ææè ¾çå°±æ¯ json ä¸¥æ ¼æ¨¡å¼å ¼å®¹ï¼åå°æ¶è§£å³ã å¦æä½ ç项ç®è¿å¨ Go 1.25 æè æ´æ©ï¼å»ºè®®æ¾ä¸ªä¸å¡ä½è°·æåä¸ä¸ãå è·æµè¯ï¼éç¹ç json ç¸å ³çæµè¯ç¨ä¾ææ²¡ææï¼å ¶ä»çå ¼å®¹æ§åºæ¬æ²¡é®é¢ã
Aitishiku.com