Когда есть свободное время я разбираюсь с языком Go, пытаюсь разобраться с его внутренностями, пытаюсь писать какие-то проекты с его помощью.
В Go вводится ряд новшеств, которых нет в других хорошо развитых и популярных языках. Соответственно, код на Go не похож на код на Java или C++, слишком уж разный набор фич, совсем другие средства выражения.
Наткнулся на прикольный способ искусственно ограничить список типов удовлетворяющих интерфейсу.
Ограничение набора типов реализующих конкретный интерфейс
К примеру если хочется использовать в своей FooFunc
функции параметр a
,
так, чтобы a мог быть разных типов, но при этом нет одного интерфейса их объединяющего,
с помощью которого можно было бы абстрагироваться.
В таких случаях используют тип interface{}
func FooFunc(a interface{}) { // do what ever you want }
Но так как как функция публичная, видимая извне, то может оказаться так,
что в качестве a
передадут не то значение что ожидает ваш код.
Как раз на этот случай есть следующий трюк, можно объявить специальный интерфейс,
который требует реализации лишь одного приватного метода-заглушки. Далее можно
объявить методы для типов которые хочется использовать, тогда тип a
будет
проверяться на стадии компиляции.
type aTypeInterface interface { aMethod() } func FooFunc(a aTypeInterface) { // do what ever you want } func (bType) aMethod(){} func (cType) aMethod(){} func (dType) aMethod(){}
Теперь параметр a
в функции FooFunc
может быть лишь одним из указанных
типов: bType
, cType
, dType
, и это проверяется на стадии компиляции.
Наткнулся на такой код в пакете стандартной библиотеки go/ast/ast.go
:
/* ... skipped ... */ // All node types implement the Node interface. type Node interface { Pos() token.Pos // position of first character belonging to the node End() token.Pos // position of first character immediately after the node } // All statement nodes implement the Stmt interface. type Stmt interface { Node stmtNode() } /* ... skipped ... */ // stmtNode() ensures that only statement nodes can be // assigned to a StmtNode. // func (*BadStmt) stmtNode() {} func (*DeclStmt) stmtNode() {} func (*EmptyStmt) stmtNode() {} func (*LabeledStmt) stmtNode() {} func (*ExprStmt) stmtNode() {} func (*SendStmt) stmtNode() {} func (*IncDecStmt) stmtNode() {} func (*AssignStmt) stmtNode() {} func (*GoStmt) stmtNode() {} func (*DeferStmt) stmtNode() {} func (*ReturnStmt) stmtNode() {} func (*BranchStmt) stmtNode() {} func (*BlockStmt) stmtNode() {} func (*IfStmt) stmtNode() {} func (*CaseClause) stmtNode() {} func (*SwitchStmt) stmtNode() {} func (*TypeSwitchStmt) stmtNode() {} func (*CommClause) stmtNode() {} func (*SelectStmt) stmtNode() {} func (*ForStmt) stmtNode() {} func (*RangeStmt) stmtNode() {}
Пример именно такого подхода