TL的Type是一个总类型Class包含不同的结构子类型实例Object,类似于Protubuf中Message与Oneof的关系。
peerUser#9db1bc6d user_id:int = Peer;
peerChat#bad0e5bb chat_id:int = Peer;
peerChannel#bddde532 channel_id:int = Peer;
folderPeer#e9baa668 peer:Peer folder_id:int = FolderPeer;
syntax = "proto3";
package tg_oneof;
option go_package = "./tg_oneof";
message Peer {
message PeerUser {
int32 user_id = 1;
}
message PeerChat {
int32 chat_id = 1;
}
message PeerChannel {
int32 channel_id = 1;
}
oneof oneofPeer {
PeerUser peerUser = 1;
PeerChat peerChat = 2;
PeerChannel peerChannel = 3;
}
}
message FolderPeer {
message FolderPeer {
oneof oneofPeer {
Peer.PeerUser peerUser = 1;
Peer.PeerChat peerChat = 2;
Peer.PeerChannel peerChannel = 3;
}
int32 folder_id = 1;
}
}
// PeerClass represents Peer generic type.
//
// Constructors:
// - [PeerUser]
// - [PeerChat]
// - [PeerChannel]
//
// Example:
//
// g, err := tg.DecodePeer(buf)
// if err != nil {
// panic(err)
// }
// switch v := g.(type) {
// case *tg.PeerUser: // peerUser#59511722
// case *tg.PeerChat: // peerChat#36c6019a
// case *tg.PeerChannel: // peerChannel#a2a5371e
// default: panic(v)
// }
type PeerClass interface {
bin.Encoder
bin.Decoder
bin.BareEncoder
bin.BareDecoder
construct() PeerClass
// TypeID returns type id in TL schema.
TypeID() uint32
// TypeName returns name of type in TL schema.
TypeName() string
// String implements fmt.Stringer.
String() string
// Zero returns true if current object has a zero value.
Zero() bool
}
// PeerChannel represents TL type `peerChannel#a2a5371e`.
// Channel/supergroup
type PeerChannel struct {
// Channel ID
ChannelID int64
}
// construct implements constructor of PeerClass.
func (p PeerChannel) construct() PeerClass { return &p }
// PeerChat represents TL type `peerChat#36c6019a`.
// Group.
type PeerChat struct {
// Group identifier
ChatID int64
}
// construct implements constructor of PeerClass.
func (p PeerChat) construct() PeerClass { return &p }
// PeerUser represents TL type `peerUser#59511722`.
// Chat partner
type PeerUser struct {
// User identifier
UserID int64
}
// construct implements constructor of PeerClass.
func (p PeerUser) construct() PeerClass { return &p }
// FolderPeer represents TL type `folderPeer#e9baa668`.
// Peer in a folder
type FolderPeer struct {
// Folder peer info
Peer PeerClass
// Peer folder ID, for more info click here¹
FolderID int
}
这里的关键是必须有某种方式约束PeerClass只能是PeerUser/PeerChat/PeerChannel之一,gotd巧妙的使用未导出方法 construct() PeerClass 来约束只有与PeerClass同一包内的实现该私有方法的PeerUser/PeerChat/PeerChannel才能赋值给PeerClass变量。
Go中 switch type 断言与Rust的match type有异曲同工之妙:
switch v := g.(type) {
case *tg.PeerUser: // peerUser#59511722
case *tg.PeerChat: // peerChat#36c6019a
case *tg.PeerChannel: // peerChannel#a2a5371e
default: panic(v)
}
match g {
tg::PeerUser(user) => // peerUser#59511722
tg::PeerChat(chat) => // peerChat#36c6019a
tg::PeerChannel(channel) => // peerChannel#a2a5371e
_ => None
}