Как узнать, реализует ли структура или указатель на структуру интерфейс - PullRequest
0 голосов
/ 07 февраля 2019

Мне нужно знать, реализует ли структура или указатель на эту структуру данный интерфейс.

// You can edit this code!
// Click here and start typing.
package main

import "fmt"

func main() {
 var a A = A{
  i: 5,
 }
 Serialize(a)
 Serialize(&a)
}

type Serializable interface {
 //Serialize() string
 //Deserialize(string)

 Serializebyte() []byte
 Deserializebyte(b []byte) (bytesRead int)
}

type A struct {
 i int
}

func (*A) Serializebyte() []byte {
 return []byte{0x00}
}

func (*A) Deserializebyte(b []byte) (bytesRead int) {
 return 0
}

func Serialize(objInt interface{}) []byte {
 // this doesn't work

 switch v := (objInt).(type) {
 case Serializable:
  fmt.Printf("I'm Serializable\n")
  return v.Serializebyte()
 }

 fmt.Printf("I'm not Serializable\n")
 return []byte{0x00}
}

// this other way also dont work
func Serialize2(objInt interface{}) []byte {
// this doesn't work
    _, isSerializable := objInt.(Serializable)
    if isSerializable{
        fmt.Printf("I'm Serializable\n")
        return objInt.(Serializable).Serializebyte()
}

    fmt.Printf("I'm not Serializable\n")
    return []byte{0x00}
}



// Stdout:
// I'm not Serializable
// I'm Serializable

Редактировать: Вы можете запустить приведенный выше код, чтобы понять, что я имею в виду.

Поскольку (*A) реализует Serializable, а не A, утверждениевыше не проходит, но я хочу знать, реализует ли (*A) Serializable или A.

Зачем мне это нужно?Потому что, если я могу это сделать, программистам не нужно знать, как работает Serializable.Если нет, программистам всегда нужно передавать указатель на Serializable и реализовывать Serializable в указателе структуры, а не в самой структуре.

Ответы [ 2 ]

0 голосов
/ 07 февраля 2019

Обычно плохая идея использовать *T, когда пользователь дает вам T.Все изменения на *T будут НЕ вступать в силу для данных пользователя.

Но если это то, что вы действительно хотите, вы можете использовать отражать.

func testFool(a interface{}) bool {
    if _, ok := a.(Fool); ok {
        return true
    }
    t := reflect.PtrTo(reflect.TypeOf(a))
    FoolType := reflect.TypeOf((*Fool)(nil)).Elem()
    return t.Implements(FoolType)
}

Детская площадка: https://play.golang.org/p/rqJe5_KAP6e

РЕДАКТИРОВАНИЕ: Если вам нужно использовать этот метод с приемником указателя, вы можете использовать reflect.Value вместо reflect.Type.Тем не менее, он создает дополнительную копию параметра.

func testFool(a interface{}) bool {
    if _, ok := a.(Fool); ok {
        return true
    }
    t := reflect.TypeOf(a)
    v := reflect.New(t)
    v.Elem().Set(reflect.ValueOf(a))
    ptrA := v.Interface()
    if foo, ok := ptrA.(Fool); ok {
        foo.Foo()
        return true
    }
    return false
}

Можно написать код версии без копирования, используя refelct.NewAt и · refle.Value.InterfaceData`.Но это крайне не рекомендуется: он, скорее всего, сломает ваш будущий код и его трудно поддерживать;Используется небезопасная упаковка под капотом.

0 голосов
/ 07 февраля 2019
func Serialize(objInt interface{}) []byte {
    switch v := objInt.(type) {
    case Serializable:
        return v.Serializebyte()
    }

    // do stuf on object that do not implement Serializebyte
}

https://tour.golang.org/methods/16

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...