偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Go語(yǔ)言的“靈魂拷問(wèn)”:接口只關(guān)乎行為,還是也應(yīng)擁抱數(shù)據(jù)?

開(kāi)發(fā) 前端
泛型約束 interface{ int | float64 }? 允許在函數(shù)內(nèi)使用 +? 操作符,正是因?yàn)樗s束了類(lèi)型集內(nèi)的所有類(lèi)型都支持 +? 這個(gè)“行為”。同理,interface{ X int }? 也可以被理解為約束了所有類(lèi)型都支持 .X 這個(gè)“操作”。

在 Go 語(yǔ)言的世界里,接口(interface)一直被視為其設(shè)計(jì)哲學(xué)的基石之一——它只關(guān)心一個(gè)類(lèi)型能做什么(行為),而不關(guān)心它是什么(結(jié)構(gòu))。這種基于方法集的鴨子類(lèi)型,賦予了 Go 獨(dú)一無(wú)二的靈活性和解耦能力。然而,隨著 Go 1.18 泛型的到來(lái),一個(gè)深刻的問(wèn)題被擺上了臺(tái)面:當(dāng)我們需要編寫(xiě)對(duì)數(shù)據(jù)的結(jié)構(gòu)而非行為具有通用性的代碼時(shí),現(xiàn)有的約束機(jī)制是否足夠?

GitHub 上的 Issue #51259,“proposal: spec: support for struct members in interface/constraint syntax”,正是這場(chǎng)“靈魂拷問(wèn)”的中心。它提出的一個(gè)看似簡(jiǎn)單的想法——讓接口能夠描述結(jié)構(gòu)體字段——卻引發(fā)了一場(chǎng)關(guān)于 Go 語(yǔ)言核心哲學(xué)的深度辯論:我們是應(yīng)該堅(jiān)守“行為至上”的純粹性,還是應(yīng)該擁抱一個(gè)更務(wù)實(shí)的、能感知數(shù)據(jù)結(jié)構(gòu)的泛型系統(tǒng)?

在這篇文章中,我就和大家一起來(lái)看看Go社區(qū)和Go團(tuán)隊(duì)關(guān)注這個(gè)提案的討論過(guò)程,以及基于當(dāng)前現(xiàn)狀的臨時(shí)決議。

問(wèn)題的根源:當(dāng)泛型遇到結(jié)構(gòu)

想象一下這個(gè)常見(jiàn)的場(chǎng)景:你需要編寫(xiě)一個(gè)通用的函數(shù),來(lái)處理一組具有共同字段的結(jié)構(gòu)體,比如各種類(lèi)型的 Kubernetes 資源,它們都內(nèi)嵌了 metav1.ObjectMeta 和 metav1.TypeMeta?;蛘?,在圖形學(xué)應(yīng)用中,你需要處理多種都包含 X、Y 字段的 Point 結(jié)構(gòu)。

在 Go 1.18 之后,我們很自然地會(huì)想到使用類(lèi)型聯(lián)合(union)來(lái)約束泛型函數(shù):

type Point2D struct { X, Y float64 }
type Point3D struct { X, Y, Z float64 }

// 期望的寫(xiě)法
func Distance[T Point2D | Point3D](p T) float64 {
   // 編譯失敗!
   // p.X undefined (type T has no field or method X)
   return math.Sqrt(p.X*p.X + p.Y*p.Y) 
}

然而,編譯器無(wú)情地拒絕了我們。原因在于,Go 的泛型約束規(guī)定,對(duì)類(lèi)型參數(shù)的操作,必須是其類(lèi)型集合中所有類(lèi)型都明確支持的。對(duì)于一個(gè)類(lèi)型聯(lián)合,其“共同能力”僅限于所有成員都實(shí)現(xiàn)的方法集,而不包括共同的字段。

為了繞過(guò)這個(gè)限制,目前唯一的辦法是回歸到 Go 的傳統(tǒng)強(qiáng)項(xiàng):行為接口。開(kāi)發(fā)者被迫為每個(gè)結(jié)構(gòu)體編寫(xiě)瑣碎的 getter/setter 方法,僅僅是為了讓它們滿(mǎn)足同一個(gè)行為接口,從而能在泛型函數(shù)中使用,但這恰恰是“樣板代碼”的來(lái)源:

import "math"

// 原始結(jié)構(gòu)體
type Point2D struct{ X, Y float64 }
type Point3D struct{ X, Y, Z float64 }

// 1. 定義一個(gè)行為接口來(lái)描述“獲取坐標(biāo)”的行為
type Point interface {
 X() float64
 Y() float64
}

// 2. 為每個(gè)結(jié)構(gòu)體實(shí)現(xiàn)接口(這部分就是樣板代碼)
func (p Point2D) X() float64 { return p.X }
func (p Point2D) Y() float64 { return p.Y }

func (p Point3D) X() float64 { return p.X }
func (p Point3D) Y() float64 { return p.Y }

// 3. 現(xiàn)在,泛型函數(shù)可以基于行為接口工作了
func Distance[T Point](p T) float64 {
// 通過(guò)方法調(diào)用,而非字段訪(fǎng)問(wèn)
return math.Sqrt(p.X()*p.X() + p.Y()*p.Y())
}

上面的代碼現(xiàn)在可以編譯通過(guò)了,但代價(jià)是什么?我們被迫編寫(xiě)了四個(gè)極其瑣碎的、僅僅是 return p.FieldName 的 getter 方法。這些方法沒(méi)有增加任何新的業(yè)務(wù)邏輯,它們存在的唯一目的,就是為了滿(mǎn)足類(lèi)型系統(tǒng)的約束。如果還需要修改字段,我們還得再為每個(gè)結(jié)構(gòu)體編寫(xiě) SetX、SetY 等 setter 方法。

當(dāng)需要約束的字段增多,或者涉及的結(jié)構(gòu)體類(lèi)型增加時(shí),這種樣板代碼會(huì)呈爆炸式增長(zhǎng)。這正是這場(chǎng)“靈魂拷問(wèn)”的開(kāi)端:為了形式上的“行為”,我們是否犧牲了實(shí)質(zhì)上的簡(jiǎn)潔與直觀(guān)?我們是否應(yīng)該有一種更直接的方式,來(lái)表達(dá)對(duì)結(jié)構(gòu)的約束?

提案的核心:讓接口描述“數(shù)據(jù)契約”

為了擺脫這種繁瑣的 “getter 樣板代碼” 困境,提案者提出了一個(gè)大膽而直觀(guān)的想法:將對(duì)結(jié)構(gòu)的要求,直接提升為接口的一部分,讓接口能夠描述一種“數(shù)據(jù)契約”。

// 提案中的核心語(yǔ)法
type TwoDimensional interface {
    X, Y int
}
    
// 泛型函數(shù)現(xiàn)在可以直接訪(fǎng)問(wèn)由約束保證存在的字段
func TwoDimensionOperation[T TwoDimensional](value T) int { 
return value.X * value.Y // 合法!
}

type Point2D struct{ X, Y int }
type Point3D struct{ X, Y, Z int }

var p2 Point2D
var p3 Point3D
TwoDimensionOperation(p2) // 編譯通過(guò)
TwoDimensionOperation(p3) // 編譯通過(guò)

這個(gè)提議的精妙之處在于,它并沒(méi)有發(fā)明一個(gè)全新的概念,而是將我們之前被迫用 行為 (getter 方法) 模擬的 結(jié)構(gòu) 約束,變成了一種一等公民。它精準(zhǔn)地回答了一個(gè)問(wèn)題:如果我們只是想要訪(fǎng)問(wèn)一個(gè)字段,為什么必須強(qiáng)制類(lèi)型去實(shí)現(xiàn)一個(gè)方法呢?為什么不能直接在約束中聲明我們對(duì)“數(shù)據(jù)契約”的要求?

一位參與討論的 Gopher 對(duì)此給出了一個(gè)絕佳的類(lèi)比,清晰地闡述了這種思想上的轉(zhuǎn)變:

“In the same way that type XGetter interface { GetX() int } represents the set of types that implement the method GetX() int, Xer would be the set of types that have a member X.” (就像 XGetter 接口代表了所有實(shí)現(xiàn)了 GetX() int 方法的類(lèi)型集合一樣,Xer 接口將代表所有擁有字段 X 的類(lèi)型集合。)

這種轉(zhuǎn)變不僅是語(yǔ)法的簡(jiǎn)化,更是思維模式的飛躍。它允許我們從“要求一個(gè) GetX() 的行為”,轉(zhuǎn)變?yōu)楦苯拥摹耙笠粋€(gè) X 字段的存在”。這不僅解決了樣板代碼的問(wèn)題,還帶來(lái)了潛在的性能優(yōu)勢(shì):編譯器可以直接生成字段訪(fǎng)問(wèn)指令,而無(wú)需像方法調(diào)用那樣進(jìn)行動(dòng)態(tài)派發(fā)(dynamic dispatch)。

激烈的辯論:行為 vs. 結(jié)構(gòu)

這個(gè)提案立即引發(fā)了社區(qū)的深度討論,核心的爭(zhēng)議點(diǎn)在于它是否動(dòng)搖了 Go 接口的哲學(xué)根基。

反對(duì)的聲音:“接口應(yīng)該只關(guān)乎行為”

一些Go社區(qū)成員的觀(guān)點(diǎn)認(rèn)為,這是對(duì) Go 接口核心理念的背離:

“It seems to shift the emphasis of interfaces from behavior to data... a mechanism for focusing on what a type can do, rather that what a type is composed of.” (這似乎將接口的重點(diǎn)從行為轉(zhuǎn)移到了數(shù)據(jù)……接口是一個(gè)專(zhuān)注于類(lèi)型能做什么,而非由什么組成的機(jī)制。)

這種觀(guān)點(diǎn)認(rèn)為,字段是數(shù)據(jù)(data)或結(jié)構(gòu)(structure),而方法是行為(behavior)。一旦接口開(kāi)始描述數(shù)據(jù),Go 就可能失去其設(shè)計(jì)上的純粹性,向更復(fù)雜的、基于結(jié)構(gòu)繼承的語(yǔ)言靠攏。

支持的聲音:“字段也是一種操作” & “泛型改變了游戲規(guī)則”

另一方則認(rèn)為,這種“行為 vs. 結(jié)構(gòu)”的二元對(duì)立在泛型時(shí)代已經(jīng)過(guò)時(shí)。Go 核心團(tuán)隊(duì)的 ianlancetaylor 提供了一個(gè)全新的視角:

“If you view field access as an operation on a type, in the same sense that + is an operation on a type, then it does make sense.” (如果你將字段訪(fǎng)問(wèn)視為一種類(lèi)型上的操作,就像 + 是一種操作一樣,那么這就說(shuō)得通了。)

泛型約束 interface{ int | float64 } 允許在函數(shù)內(nèi)使用 + 操作符,正是因?yàn)樗s束了類(lèi)型集內(nèi)的所有類(lèi)型都支持 + 這個(gè)“行為”。同理,interface{ X int } 也可以被理解為約束了所有類(lèi)型都支持 .X 這個(gè)“操作”。

此外,支持者認(rèn)為,Go 1.18 引入的類(lèi)型聯(lián)合本身,就已經(jīng)讓接口開(kāi)始描述“是什么”(具體的類(lèi)型集合),而不僅僅是“能做什么”了。因此,允許接口描述結(jié)構(gòu),只是這一演進(jìn)方向上合乎邏輯的下一步。

深層挑戰(zhàn):可寫(xiě)性、嵌入與接口值

除了哲學(xué)辯論,討論還深入到了一些棘手的技術(shù)細(xì)節(jié):

  • 字段的可寫(xiě)性(Addressability): 如果一個(gè)泛型函數(shù)可以修改字段 (point.X = 1.0),當(dāng)傳入一個(gè)非指針的結(jié)構(gòu)體值時(shí),修改應(yīng)該只發(fā)生在函數(shù)內(nèi)部的副本上。但如果傳入的是一個(gè)接口值,其底層動(dòng)態(tài)值的可寫(xiě)性如何保證?這引出了關(guān)于“可寫(xiě)字段”約束的復(fù)雜討論,例如用 *Y int 語(yǔ)法來(lái)表示可寫(xiě)字段。
  • 嵌入字段(Embedded Fields): 如何在接口中表達(dá)一個(gè)類(lèi)型必須“嵌入”另一個(gè)類(lèi)型,而不僅僅是擁有其所有字段?這涉及到類(lèi)型布局和方法提升等更深層次的語(yǔ)義,目前尚無(wú)完美的解決方案。
  • 接口值化: ianlancetaylor 明確指出,任何被接受的約束提案,都應(yīng)該有潛力在未來(lái)演進(jìn)為可被實(shí)例化的普通接口類(lèi)型。一個(gè)只能作為約束存在的“半成品”接口,會(huì)給語(yǔ)言增加不必要的復(fù)雜性。

結(jié)論:一個(gè)被擱置但遠(yuǎn)未結(jié)束的探索

最終,由于其巨大的復(fù)雜性和對(duì)語(yǔ)言核心概念的深遠(yuǎn)影響,Go 團(tuán)隊(duì)決定將此提案擱置(On Hold),以便在社區(qū)對(duì) Go 1.18 泛型有了更充分的實(shí)踐和理解后再做定奪。

然而,這場(chǎng)辯論的價(jià)值遠(yuǎn)超提案本身。它強(qiáng)迫我們重新思考 Go 語(yǔ)言的核心概念在泛型時(shí)代下的新內(nèi)涵。它揭示了在 Kubernetes API 操作、數(shù)據(jù)庫(kù) ORM、圖形學(xué)庫(kù)等真實(shí)世界場(chǎng)景中,對(duì)“結(jié)構(gòu)化泛型”的迫切需求。

雖然我們短期內(nèi)不會(huì)看到 interface{ X int } 這樣的語(yǔ)法,但這場(chǎng)討論已經(jīng)播下了種子。它可能會(huì)在未來(lái)以某種形式回歸,或許是更完善的接口語(yǔ)法。Issue #51259 的開(kāi)放狀態(tài),本身就代表著一種承諾:關(guān)于 Go 語(yǔ)言靈魂的探索,遠(yuǎn)未結(jié)束。

責(zé)任編輯:武曉燕 來(lái)源: TonyBai
相關(guān)推薦

2021-02-23 08:58:13

Go語(yǔ)言變量

2020-06-02 07:44:04

AQS JavaNode

2021-02-24 10:01:05

機(jī)器學(xué)習(xí)人工智能計(jì)算機(jī)

2025-10-29 16:29:27

OpenAIGPT-2模型

2022-05-30 18:37:03

數(shù)據(jù)個(gè)人信息人工智能

2019-11-19 10:32:55

Java語(yǔ)言程序員

2022-12-12 08:46:11

2020-05-22 08:13:45

敏捷開(kāi)發(fā)OKR

2019-08-12 11:14:00

JVM垃圾對(duì)象

2020-05-29 11:48:01

安全運(yùn)維信息安全網(wǎng)絡(luò)安全

2025-05-19 17:18:57

AI模型o3

2022-03-16 18:27:39

開(kāi)發(fā)低代碼軟件開(kāi)發(fā)

2022-08-26 01:10:32

TCPSYNLinux

2019-08-01 10:20:10

2021-03-05 14:58:34

比特幣區(qū)塊鏈挖礦

2021-05-26 05:22:48

SQL 數(shù)據(jù)庫(kù)SELECT

2023-06-16 14:10:00

TCPUDP網(wǎng)絡(luò)通信

2020-11-24 09:50:22

大數(shù)據(jù)語(yǔ)言go

2021-03-12 09:24:58

Redis面試場(chǎng)景

2021-06-02 09:47:48

RSA2021
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)