首頁 >後端開發 >Golang >如何確定泛型類型在運行時是否「可比較」?

如何確定泛型類型在運行時是否「可比較」?

WBOY
WBOY轉載
2024-02-05 21:54:03588瀏覽

如何確定泛型類型在運行時是否「可比較」?

問題內容

我想寫一個通用的 equals 方法,其工作原理如下:

func equals[T any](a, b T) bool {
  if hasEqualsMethod(T) {
    return a.Equals(b)
  else if isComparable(T) {
    return a == b
  }
  panic("type cannot be compared")
} 

為此,我創建了一個介面 comparable

type Comparable[T any] interface {
    // Equals returns true if the receiver and the argument are equal.
    Equals(T) bool
}

我可以檢查 equals 的參數是否實作了這個 comparable 接口,如下所示:

func equals[T any](a, b T) bool {
    aComp, ok := any(a).(Comparable[T])
    if ok {
        return aComp.Equals(b)
    }
    ...

但是,到目前為止,我發現不可能找出 a 是否也滿足 comparable 約束並將其轉換為可以使用 == 的內容。

有沒有辦法找出泛型類型T any 在運行時是否是comparable ,如果是,則使用== 進行比較?

我可以限制我的整個程式碼僅適用於comparable 泛型類型,但我想讓使用者可以手動新增equals 方法,如果他們的類型恰好不是 comparable (例如,因為它是基於切片) )。


正確答案


如果它使用相等運算子進行編譯,則它是可比較的。受 any 約束的類型參數在定義上是不可比較的:它實際上可以是任何內容,包括 func() error

因此不可能使用靜態型別來寫 equals 函數。您必須使用反射或僅接受實現「相等」介面的參數,例如您自己的 Comparable[T any]

透過反射,您可以使用Value#Comparable

func equals[T any](a, b T) bool {
    v := reflect.ValueOf(a)
    if v.Comparable() {
        u := reflect.ValueOf(b)
        return v.Equal(u)
    }
    panic("type cannot be compared")
}

在這種情況下,使用泛型可能有助於在編譯時確保ab 具有相同的確切類型,因此v.Equal(u) 不是毫無意義的,而不是宣告equals(a, b any)

使用「equaler」接口,您必須提供實作它的命名類型,以便轉換預先聲明的類型並呼叫它們的方法:

func main() {
    fmt.Println(equals(EqualerFloat64(5.57), EqualerFloat64(5.57)))
}

type Equaler[T any] interface {
    Equal(T) bool
}

type EqualerFloat64 float64

func (f EqualerFloat64) Equal(f2 EqualerFloat64) bool {
    return f == f2
}

func equals[T Equaler[T]](a, b T) bool {
    return a.Equal(b)
}

以上是如何確定泛型類型在運行時是否「可比較」?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除