func (v Vector) String() string {
	var sb strings.Builder
	fmt.Fprintf(&sb, "%s%s/", prefix, v.version)
	defineables := v.definables()
	first := true
	for _, metric := range order {
		def := defineables[metric]
		if !def.defined() {
			continue
		}
		if !first {
			fmt.Fprint(&sb, partSeparator)
		} else {
			first = false
		}
		fmt.Fprintf(&sb, "%s%s%s", metric, metricSeparator, def)
	}
	return sb.String()
}
String returns this vectors representation as a string
it shouldn't depend on the order of metrics
package cvss3
import (
	"fmt"
	"strings"
)
const (
	prefix          = "CVSS:"
	partSeparator   = "/"
	metricSeparator = ":"
)
type version int
func (v version) String() string {
	return fmt.Sprintf("3.%d", int(v))
}
func versionFromString(v string) (version, error) {
	switch v {
	case "3.0":
		return version(0), nil
	case "3.1":
		return version(1), nil
	default:
		return version(0), fmt.Errorf("cvss v3 version %s not supported", v)
	}
}
type Vector struct {
	version version
	BaseMetrics
	TemporalMetrics
	EnvironmentalMetrics
}
var undefinedEquivalent = map[string]string{
	"E":  "H",
	"RL": "U",
	"RC": "C",
	"CR": "M",
	"IR": "M",
	"AR": "M",
}
func equivalent(metric, value string) string {
	if value != "X" {
		return value
	}
	e, ok := undefinedEquivalent[metric]
	if !ok {
		return value
	}
	return e
}
func (v Vector) Equal(o Vector) bool {
	vDefs := v.definables()
	oDefs := o.definables()
	for _, metric := range order {
		a := equivalent(metric, vDefs[metric].String())
		b := equivalent(metric, oDefs[metric].String())
		if a != b {
			return false
		}
	}
	return true
}