func (g *DirectedGraph) Value(key string) (interface{}, error) {
	g.lock.RLock()
	defer g.lock.RUnlock()
	if _, ok := g.nodes[key]; !ok {
		return nil, ErrorNodeNotFound
	}
	value := g.nodes[key]
	return value, nil
}
Value retrieves the value assigned to the node identified by key
package directedgraph
import (
	"bytes"
	"fmt"
	"sync"
)
var (
	ErrorNodeNotFound = fmt.Errorf("node not found")
	ErrorNodeAlreadyExists = fmt.Errorf("node already exists")
	ErrorGraphIsCyclic = fmt.Errorf("graph is cyclic")
)
type DirectedGraph struct {
	lock  sync.RWMutex
	nodes map[string]interface{}
	edges map[string]map[string]bool
}
func New() *DirectedGraph {
	return &DirectedGraph{
		nodes: make(map[string]interface{}),
		edges: make(map[string]map[string]bool),
	}
}
func (g *DirectedGraph) NewNode(key string, value interface{}) error {
	g.lock.Lock()
	defer g.lock.Unlock()
	if _, ok := g.nodes[key]; ok {
		return ErrorNodeAlreadyExists
	}
	g.nodes[key] = value
	g.edges[key] = make(map[string]bool)
	return nil
}