go / types.Identical не может сравнивать два одинаковых типа в другом пакете? - PullRequest
0 голосов
/ 13 октября 2018

Я пишу некоторый код, чтобы получить специальный тип по "go / types"

import (
    "go/ast"
    "go/importer"
    "go/parser"
    "go/token"
    "go/types"
    "log"
)    

const (
    Src = `
package types

import (
    "io"
    "net/http"
)

var (
    IOReader    io.Reader
    Err         error
    StatusCode  int
    Request     *http.Request
    Response    *http.Response
)
`
)

const (
    TypeIOReader   = "IOReader"
    TypeErr        = "Err"
    TypeStatusCode = "StatusCode"
    TypeRequest    = "Request"
    TypeResponse   = "Response"
)


func GetType(name string) types.Type {
    fset := token.NewFileSet()
    file, err := parser.ParseFile(fset, "types.go", Src, 0)
    if err != nil {
        log.Fatal(err)
    }

    conf := types.Config{Importer: importer.Default()}
    pkg, err := conf.Check("impler/types", fset, []*ast.File{file}, nil)
    return pkg.Scope().Lookup(name).Type()
}

Функция GetType(name string) types.Type может сделать это.

И когда я сравниваю два типа, я получаюнекоторые странные результаты

log.Println(types.Identical(GetType(TypeResponse), GetType(TypeResponse)))
log.Println(types.Identical(GetType(TypeIOReader), GetType(TypeIOReader)))
log.Println(types.Identical(GetType(TypeStatusCode), GetType(TypeStatusCode)))
log.Println(types.Identical(GetType(TypeErr), GetType(TypeErr)))

Результат

false
false
true
true

Кажется, types.Identical не может сравнивать два одинаковых типа в другом пакете?Как я могу их сравнить?

Достаточно ли надежен types.TypeString(typ1, nil) == types.TypeString(typ2, nil)? 1017 *

Ответы [ 2 ]

0 голосов
/ 13 октября 2018

Проблема заключается в том, что вы каждый раз повторно анализируете исходный код, создавая новый экземпляр types.Package и связанные с ним types.Scope, что приводит к типам с именем , происходящим из разных объявлений ( ссылка ).

Встроенные типы, такие как int и error, для которых вы получили true, являются базовыми типами, которые по-разному трактуются при сравнении ( ссылка ),Они также объявлены в области «вселенная», которая, я считаю, всегда одна и та же, независимо от того, сколько раз вы повторно анализируете Src ( ссылка ).

Исправитьваша проблема, вы должны проанализировать источник один раз, а затем поделиться полученным *types.Package.

package main

import (
    "go/ast"
    "go/importer"
    "go/parser"
    "go/token"
    "go/types"
    "log"
)

const Src = `
package types

import (
    "io"
    "net/http"
)

var (
    IOReader    io.Reader
    Response    *http.Response
)
`


const (
    TypeIOReader = "IOReader"
    TypeResponse = "Response"
)

func GetType(name string, pkg *types.Package) types.Type {
    return pkg.Scope().Lookup(name).Type()
}

func main() {
    fset := token.NewFileSet()
    file, err := parser.ParseFile(fset, "types.go", Src, 0)
    if err != nil {
        panic(err)
    }

    conf := types.Config{Importer: importer.Default()}
    pkg, err := conf.Check("impler/types", fset, []*ast.File{file}, nil)
    if err != nil {
        panic(err)
    }

    log.Println(types.Identical(GetType(TypeResponse, pkg), GetType(TypeResponse, pkg)))
    log.Println(types.Identical(GetType(TypeIOReader, pkg), GetType(TypeIOReader, pkg)))
}
0 голосов
/ 13 октября 2018

Типы в Go с разными именами рассматриваются как разные, даже если они имеют одинаковую структуру.Вот дополнительная информация о правилах типа Голанга: https://golang.org/ref/spec#Type_identity

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

     type A {...} // some declaration

     type B {...} // the same declaration 

     if a == A(b) {...}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...