packagepersonnummerimport("math""reflect""regexp""strconv""time")// luhn will test if the given string is a valid luhn string.
funcluhn(strstring)int{sum:=0fori,r:=rangestr{c:=string(r)v,_:=strconv.Atoi(c)v*=2-(i%2)ifv>9{v-=9}sum+=v}returnint(math.Ceil(float64(sum)/10)*10-float64(sum))}// testDate will test if date is valid or not.
functestDate(centurystring,yearstring,monthstring,daystring)bool{t,err:=time.Parse("01/02/2006",month+"/"+day+"/"+century+year)iferr!=nil{returnfalse}y,_:=strconv.Atoi(century+year)m,_:=strconv.Atoi(month)d,_:=strconv.Atoi(day)ify>time.Now().Year(){returnfalse}return!(t.Year()!=y||int(t.Month())!=m||t.Day()!=d)}// getCoOrdinationDay will return co-ordination day.
funcgetCoOrdinationDay(daystring)string{d,_:=strconv.Atoi(day)d-=60day=strconv.Itoa(d)ifd<10{day="0"+day}returnday}// Valid will validate Swedish social security numbers.
funcValid(strinterface{})bool{ifreflect.TypeOf(str).Kind()!=reflect.Int&&reflect.TypeOf(str).Kind()!=reflect.String{returnfalse}pr:=""ifreflect.TypeOf(str).Kind()==reflect.Int{pr=strconv.Itoa(str.(int))}else{pr=str.(string)}re,_:=regexp.Compile(`^(\d{2}){0,1}(\d{2})(\d{2})(\d{2})([\-|\+]{0,1})?(\d{3})(\d{0,1})$`)match:=re.FindStringSubmatch(pr)iflen(match)==0{returnfalse}century:=match[1]year:=match[2]month:=match[3]day:=match[4]num:=match[6]check:=match[7]iflen(century)==0{yearNow:=time.Now().Year()years:=[...]int{yearNow,yearNow-100,yearNow-150}for_,yi:=rangeyears{ys:=strconv.Itoa(yi)ifValid(ys[:2]+pr){returntrue}}returnfalse}iflen(year)==4{year=year[2:]}c,_:=strconv.Atoi(check)valid:=luhn(year+month+day+num)==c&&len(check)!=0ifvalid&&testDate(century,year,month,day){returnvalid}day=getCoOrdinationDay(day)returnvalid&&testDate(century,year,month,day)}

Reflect package

Reflection is generally slow and is not made to be used in such cases. Here it
is used to check if the input type in int or string. Let’s assume we actually need
a function that accepts an interface, and not just a string.

To check the type of an interface you don’t need a reflect package. You can always
switch on an interface type:

Results are pretty much the same. I think it’s because of some compiler optimizations
where switch v.(type) is syntax sugar for reflect.TypeOf(v), plus undercover all
objects know what types they are even when you use them as an interface{}.

Time package

Standard time package is great, but what we need here is just simple validation
of a date:

varmonthDays=map[int]int{1:31,3:31,4:30,5:31,6:30,7:31,8:31,9:30,10:31,11:30,12:31,}// testDate will test if date is valid or not.
functestDate(centurystring,yearstring,monthstring,daystring)bool{y,err:=strconv.Atoi(century+year)iferr!=nil{returnfalse}m,err:=strconv.Atoi(month)iferr!=nil{returnfalse}d,err:=strconv.Atoi(day)iferr!=nil{returnfalse}ifm!=2{days,ok:=monthDays[m]if!ok{returnfalse}returnd<=days}leapYear:=y%4==0&&y%100!=0||y%400==0ifleapYear{returnd<=29}returnd<=28}

Strings

Notice that there are still 33 allocations per function call. Where do they come
from? It’s because we use string type all the time, string is the same thing
as a []byte, but immutable. So every time we call cleanNumber += string(c),
allocation happens. It’s impossible to change the string, so new the string is allocated,
and both strings are copies there.