Requirement
Hey there, I am trying to show the comments on an HTML page. Although it prints every comment in the terminal but does not show every comment on an HTML page. Instead, it shows only the first row.
Code info
After finding the data of comments in the database, I printed every comment in the terminal using the multidimensional array but it was difficult to write x and y each time. That's why I created two for-loops and a third loop to assign numbers to the values variable.
mdArray := [][]string{
values[0:4],
values[4:8],
// x:y
}
I used mdArray in the CommentData{} structure to assign values to the variables. After printing the data, it shows every comment that is inserted but when I return this function to be executed on the HTML page, it only prints the first row.
Code
type CommentData struct {
Fname string
Lname string
Email string
Message string
Date string
Time string
}
func SendData(w http.ResponseWriter, r *http.Request) CommentData {
note := models.AddComment{
Fname: r.FormValue("fname"),
Lname: r.FormValue("lname"),
Email: r.FormValue("email"),
Message: r.FormValue("message"),
}
dt := time.Now()
date := dt.Format("02-Jan-2006")
time := dt.Format("15:04:05")
values1 := [6]string{note.Fname, note.Lname, note.Email, note.Message, date, time}
_, match := database.FindAccount(note.Fname, note.Lname, note.Email)
if match {
database.InsertComment(values1)
values2 := database.FindComment(note.Fname, note.Lname, note.Email)
var store1, store2 []int
for i := 0; i <= len(values2); i++ {
if i%6 == 0 {
store1 = append(store1, i)
}
}
for j := 6; j <= len(values2); j++ {
if j%6 == 0 {
store2 = append(store2, j)
}
}
for i := 0; i < len(store2); i++ {
mdArray := [][]string{
values2[store1[i]:store2[i]],
}
// fmt.Println(mdArray[0][3])
hello := CommentData{
Fname: mdArray[0][0],
Lname: mdArray[0][1],
Email: mdArray[0][2],
Message: mdArray[0][3],
Date: "On " + mdArray[0][4],
Time: "At " + mdArray[0][5],
}
fmt.Println(hello)
return hello
}
} else {
http.Redirect(w, r, "/login", http.StatusFound)
}
return CommentData{}
}
func FirstBlog(w http.ResponseWriter, r *http.Request) error {
if r.Method == "GET" {
return FirstBlogTmpl.Execute(w, nil)
} else if r.Method == "POST" {
Newsletter(w, r)
hello := SendData(w, r)
return FirstBlogTmpl.Execute(w, hello)
}
return nil
}
HTML
<div>
{{.}}
</div>
Put resultatos in a slice:
…
var hellos []CommentData
for i := 0; i < len(store2); i++ {
mdArray := [][]string{
values2[store1[i]:store2[i]],
}
// fmt.Println(mdArray[0][3])
hello := CommentData{
Fname: mdArray[0][0],
Lname: mdArray[0][1],
Email: mdArray[0][2],
Message: mdArray[0][3],
Date: "On " + mdArray[0][4],
Time: "At " + mdArray[0][5],
}
fmt.Println(hello)
hellos = append(hellos, hello)
}
return hellos
…
Change function return type return type []CommentData.
Range over the resultatos in the template
{{range .}}
<div>
{{.}}
</div>
Related
I have this structure
type Library struct {
Book Book
Owner Owner
Editorial Editorial
}
and I had to modify one of the tags of the auto-generated Book structure from category to categoryID.
type Book struct {
ID string `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Category string `json:"category"`
}
My question is, after modifying those fields and getting correct structure of Book, how can I set it to become the new struct in Library.Book?
My code:
func renameTags(p any, m map[string]string) any {
rv := reflect.ValueOf(p)
re := rv.Elem()
rt := rv.Elem().Type()
fields := make([]reflect.StructField, rt.NumField())
for i := range fields {
f := rt.Field(i) // Book i == 0
if f.Type.Kind() == reflect.Struct && f.Type.Name() == "Book" {
fields2 := make([]reflect.StructField, f.Type.NumField()) // f == Book
for j := 0; j < f.Type.NumField(); j++ {
subField := f.Type.Field(j)
tag := subField.Tag.Get("json")
if v, ok := m[tag]; ok {
subField.Tag = reflect.StructTag(`json:"` + v + `"`)
}
fields2[j] = subField // change structure of Book
}
// here how to append new structure to f ?
//kk := reflect.StructOf(fields2).Elem()
}
fields[i] = f
}
st := reflect.StructOf(fields)
return rv.Convert(reflect.PtrTo(st)).Interface()
}
Any advice will be very much appreciated, thanks!
You can use reflect.New to create a new instance of the modified structure, then assign the value to the appropriate field in the original struct. Here's an updated code:
func renameTags(p any, m map[string]string) any {
rv := reflect.ValueOf(p)
re := rv.Elem()
rt := rv.Elem().Type()
fields := make([]reflect.StructField, rt.NumField())
for i := range fields {
f := rt.Field(i) // Book i == 0
if f.Type.Kind() == reflect.Struct && f.Type.Name() == "Book" {
fields2 := make([]reflect.StructField, f.Type.NumField()) // f == Book
for j := 0; j < f.Type.NumField(); j++ {
subField := f.Type.Field(j)
tag := subField.Tag.Get("json")
if v, ok := m[tag]; ok {
subField.Tag = reflect.StructTag(`json:"` + v + `"`)
}
fields2[j] = subField // change structure of Book
}
newStruct := reflect.New(reflect.StructOf(fields2))
re.Field(i).Set(newStruct)
}
fields[i] = f
}
st := reflect.StructOf(fields)
return rv.Convert(reflect.PtrTo(st)).Interface()
}
I’m looking to iterate through an interfaces keys.
Goal:
I want to implement a kind of middleware that checks for outgoing data (being marshalled to JSON) and edits nil slices to empty slices.
It should be agnostic/generic so that I don't need to specify field names. Ideally I can pass any struct as an interface and replace nil slices with empty slices.
Controller level
type Tag struct {
Name string
}
type BaseModel struct {
ID uuid.UUID
Active bool
}
type Model struct {
BaseModel // embedded struct
Name string
Number int
Tags []Tag
}
newModel, err := GetModel()
if err != nil {
...
}
RespondAsJson(w, newModel)
Middleware / Middle man json responder
It takes an interface to be generic/agnostic and reusable
in many different controllers
//(1) Attempting to use a map
func RespondWithJson(w http.ResponseWriter, data interface{}) {
obj, ok := data.(map[string]interface{})
// (1.1) OK == false
obj, ok := data.(map[interface{}]interface{})
// (1.2) OK == false
var newMap map[string]interface{}
bytes, _ := json.Marshal(&obj)
json.unMarshal(bytes, &newMap)
// (1.3) newMap has no underlying types on fields
// Nil slice of Tags went in, and it comes out as
// value=nil and type=interface{}
}
//(2) Skipping two as I believe this works, I'd like to avoid implementing it though.
//(3)
//(3.1)
RespondWithJson(w, newModel)
func RespondWithJson(w http.ResponseWriter, data interface{}) {
e := reflect.ValueOf(&data) // data = {*interface{} | Model}
if e.Kind() == reflect.Pointer {
e = e.Elem()
// e has a flag of 22, e.Elem() has a flag of 404
}
for i := 0; i < e.NumField(); i++ {
//PANIC: reflect: call of reflect.Value.NumField on interface Value
...
}
}
//(3.2)
// Reference: https://go.dev/blog/laws-of-reflection (third law)
RespondWithJson(w, newModel)
func RespondWithJson(w http.ResponseWriter, data interface{}) {
e := reflect.ValueOf(data) // data = {interface{} | Model}
if e.Kind() == reflect.Pointer {
e = e.Elem()
}
for i := 0; i < e.NumField(); i++ {
field := e.Field(i)
if field.Kind() == reflect.Slice && field.isNil() {
ok := field.CanSet() // OK == false
// Reference third law description in the reference above
valueOfField1 := reflect.ValueOf(&field)
ok := valueOfField1 .CanSet() // OK == false
...
valueOfField2 := reflect.ValueOf(field.Interface())
ok := valueOfField2.CanSet() // OK == false
...
}
}
}
//(3.3)
// Reference: (https://stackoverflow.com/questions/64211864/setting-nil-pointers-address-with-reflections) and others like it
RespondWithJson(w, newModel)
func RespondWithJson(w http.ResponseWriter, data interface{}) {
e := reflect.ValueOf(data) // {interface{} | Model}
if e.Kind() == reflect.Pointer { e = e.Elem() }
for i := 0; i < e.NumField(); i++ {
field := e.Field(i)
if field.Kind() == reflect.Slice && field.IsNil() {
tmp := reflect.New(field.Type())
if tmp.Kind() == reflect.Pointer { tmp = tmp.Elem()}
// (3.3.1)
ok := tmp.CanSet() // OK == true
tmp.Set(reflect.MakeSlice(field.Type(),0,0))
ok := field.CanSet()
// OK == false, tmp.set doesn't affect field value && can't set
field with value of tmp
// (3.3.2)
ok := tmp.Elem().CanSet()
// PANIC - call of reflect.value.Elem on Slicevalue
...
}
}
}
//(3.4)
// I can get it to work with passing &model to the function
// Once I'm inside the function, it's seen as an interface (or a
// *interface and the above is my results
RespondWithJson(w, &newModel)
func RespondWithJson(w http.ResponseWriter, data interface{}) {
e := reflect.ValueOf(data) // Data is {interface{} | *Model}
if e.Kind() == reflect.Pointer {
e = e.Elem()
// e has a flag of 22, e.Elem() has a flag of 409
}
for i := 0; i < e.NumField(); i++ {
field := e.Field(i)
if field.Kind() == reflect.Slice && field.IsNil() {
ok := field.CanSet()
// OK == true, field is addressable
if ok {
field.Set(reflect.MakeSlice(field.Type(), 0, 0))
// Success! Tags: nil turned into Tags: []
}
}
}
}
After that and many more.. random interations, I've found a way to make it work by passing memory address of struct to function which takes interface value.
If possible, I'd like to avoid the need to do this, as the function signature won't pick it up and it just leaves a small amount of room for error for other people on my team. I can of course just document the function, but its not bullet proof :)
Does anyone have suggestions for making this work without starting with a memory address to a struct? Can I set a field of an interface? ty very much!
In general, what you're probably looking for is something involving reflection. Your current code:
func someFunction(data interface{}) {
y := reflect.ValueOf(&data)
for i := 0; i < y.NumField(); i++ {
// PANIC: y is not a value of a struct
}
}
is pretty close, but it fails because data is a pointer. You can fix this by doing:
y := reflect.ValueOf(data)
if y.Kind() == reflect.Pointer {
y = y.Elem()
}
This will ensure that you have the actual value, and not a pointer to the value, allowing you to do NumField on it. Inside the loop, you check if the field is a slice and if it's nil and then set it to the value of a new instance of a slice of your field's type.
yField := y.Field(i)
if yField.Kind() == reflect.Slice && yField.IsNil() {
yField.Set(reflect.MakeSlice(yField.Elem().Type(), 0, 0)
}
Here we use Elem again because yField points to a slice, and so to create a new slice we need the inner type.
Finally, you need to add recursion to handle inner types if any of your fields are structs:
func SomeFunction(data interface{}) ([]byte, error) {
someFunctionInner(reflect.ValueOf(data))
return json.Marshal(data)
}
func someFunctionInner(v reflect.Value) {
if v.Kind() == reflect.Pointer {
v = v.Elem()
}
for i := 0; i < v.NumField(); i++ {
vField := v.Field(i)
switch vField.Kind() {
case reflect.Slice:
if vField.IsNil() {
vField.Set(reflect.MakeSlice(vField.Type(), 0, 0))
} else {
for j := 0; j < vField.Len(); j++ {
vFieldInner := vField.Index(j)
if vFieldInner.Kind() != reflect.Struct &&
(vFieldInner.Kind() != reflect.Pointer || vFieldInner.Elem().Kind() != reflect.Struct) {
continue
}
someFunctionInner(vFieldInner.Index(j))
}
}
case reflect.Pointer, reflect.Struct:
someFunctionInner(vField)
default:
}
}
}
and then you call it like this:
func main() {
m := Model{}
b, d := SomeFunction(&m)
fmt.Printf("Data: %+v\n", m)
fmt.Printf("JSON: %s, Error: %v\n", b, d)
}
Data: {BaseModel:{ID: Active:false} Name: Number:0 Tags:[]}
JSON: {"ID":"","Active":false,"Name":"","Number":0,"Tags":[]}, Error: <nil>
Note that I haven't added any sort of error-handling. Nor have I handled anything above regular pointers. Also, this function does expect a reference to an object because it is making modifications to said object. Finally, this code doesn't touch array logic at all. Still, this is likely what you're looking for.
I think I need a better solution than my case switch as the struct gains more fields my function will become verbose. Is there a way to swap my switch for a loop?
I have the following code
type Things struct {
StreetNames []string `json:"streetNames"`
Letters []string `json:"letters"`
MaleNames []string `json:"maleNames"`
}
func CheckCategories(data *Things, filePath string) error {
errMsg := "list has no values or is a missing category in File: " + filePath
categories := []string{"street_name", "letter", "male_first_name"}
for _, value := range categories {
switch value {
case "street_name":
if len(data.StreetNames) == 0 {
return errors.New("street_name " + errMsg)
}
case "letter":
if len(data.Letters) == 0 {
return errors.New("letter " + errMsg)
}
case "male_first_name":
if len(data.MaleNames) == 0 {
return errors.New("male_first_name " + errMsg)
}
}
}
return nil
}
This works for me but the real struct contains 12 fields which makes my functions long and repetitive.
I tried
for _, value := range categories {
if len("data." + value) == 0 {
return errors.New(value + errMsg)
}
But when I ran the code I took a moment to notice it wasn't working as intended, Im getting the length of the string. I have tried data[value] but that didn't work either.
Is there a way to swap my switch for a loop?
You could do the following:
type Things struct {
StreetNames []string `json:"streetNames"`
Letters []string `json:"letters"`
MaleNames []string `json:"maleNames"`
}
func CheckCategories(data *Things, filePath string) error {
errMsg := "list has no values or is a missing category in File: " + filePath
categories := []struct{
name string
slice []string
}{
{"street_name", data.StreetNames},
{"letter", data.Letters},
{"male_first_name", data.MaleNames},
}
for _, v := range categories {
if len(v.slice) == 0 {
return errors.New(v.name + " " + errMsg)
}
}
return nil
}
I'm trying to write a generic function to do a partial update for row, Here is what I got so far.
func GetSetByUpdateOptions(x interface{}) (string, error) {
t := reflect.TypeOf(x)
v := reflect.ValueOf(x)
if v.Kind() != reflect.Struct {
return "", errors.New("invalid_options_tag")
}
res := "SET "
for i := 0; i < v.NumField(); i++ {
setTemplate := "%s=%v, "
field := t.Field(i).Tag.Get("sql_set")
value := v.Field(i).Interface()
// NEED TO CHECK VALUE HERE
if field == "" {
return "", errors.New("invalid_options_tag")
}
res += fmt.Sprintf(setTemplate, field, value)
}
return res, nil
}
type Optional struct {
Field1 *int `set:"field1"` // might be nil if not set
Field2 *int `set:"field2"` // might be nil if not set
}
func UpdateRow(o Optional) { // here because i want a partial update. field1
s, _ := GetSetByUpdateOptions(o)
query := "UPDATE table SET status=" + s + " mtime=UNIX_TIMESTAMP(NOW()) WHERE id = ?"
// update
}
Just wondering how to define an input type since using an interface as input for GetSetByUpdateOptions seems not a good idea and How to filter some part of options because I want a partial update?
I'm quite a basic Go programmer and I've been taking a look at this small Scheme interpreter and I've been trying to understand how it works.
I found it here:
https://pkelchte.wordpress.com/2013/12/31/scm-go/
I read the webpage, but I'm still struggling to understand how it works because the source code is obviously written by someone who's a lot more familiar with Go than I am.
Particularly there's these lines that I'm struggling to understand:
e := expression.(type) // Line 73
I'm not sure what the .(type) part means, I thought it was casting but it doesn't look like the casting I've seen before.
switch p := procedure.(type) {
case func(...scmer) scmer:
value = p(args...)
case proc:
en := &env{make(vars), p.en}
switch params := p.params.(type) {
case []scmer:
for i, param := range params {
en.vars[param.(symbol)] = args[i]
}
default:
en.vars[params.(symbol)] = args
}
value = eval(p.body, en)
I don't really understand any of this code to be honest. Lines 73 - 86
*tokens = (*tokens)[1:] // Line 208
I'm not sure what this line means due to it's weird syntax. I get that its pointers and that the parenthesises are because of the *. But I'm not sure what that lines doing.
Finally there's these lines:
token := (*tokens)[0]
*tokens = (*tokens)[1:]
switch token {
case "(": //a list begins
L := make([]scmer, 0)
for (*tokens)[0] != ")" {
if i := readFrom(tokens); i != symbol("") {
L = append(L, i)
}
}
*tokens = (*tokens)[1:]
return L
I don't know what these lines do either. Lines 198 - 209
Here's the complete code if you want it, I realise it's 250 lines long but I'd really appreciate as many explanations about what its doing as possible.
/*
* A minimal Scheme interpreter, as seen in lis.py and SICP
* http://norvig.com/lispy.html
* http://mitpress.mit.edu/sicp/full-text/sicp/book/node77.html
*
* Pieter Kelchtermans 2013
* LICENSE: WTFPL 2.0
*/
package main
import (
"bufio"
"fmt"
"log"
"os"
"reflect"
"strconv"
"strings"
)
func main() {
Repl()
}
/*
Eval / Apply
*/
func eval(expression scmer, en *env) (value scmer) {
switch e := expression.(type) {
case number:
value = e
case symbol:
value = en.Find(e).vars[e]
case []scmer:
switch car, _ := e[0].(symbol); car {
case "quote":
value = e[1]
case "if":
if eval(e[1], en).(bool) {
value = eval(e[2], en)
} else {
value = eval(e[3], en)
}
case "set!":
v := e[1].(symbol)
en.Find(v).vars[v] = eval(e[2], en)
value = "ok"
case "define":
en.vars[e[1].(symbol)] = eval(e[2], en)
value = "ok"
case "lambda":
value = proc{e[1], e[2], en}
case "begin":
for _, i := range e[1:] {
value = eval(i, en)
}
default:
operands := e[1:]
values := make([]scmer, len(operands))
for i, x := range operands {
values[i] = eval(x, en)
}
value = apply(eval(e[0], en), values)
}
default:
log.Println("Unknown expression type - EVAL", e)
}
return
}
func apply(procedure scmer, args []scmer) (value scmer) {
switch p := procedure.(type) {
case func(...scmer) scmer:
value = p(args...)
case proc:
en := &env{make(vars), p.en}
switch params := p.params.(type) {
case []scmer:
for i, param := range params {
en.vars[param.(symbol)] = args[i]
}
default:
en.vars[params.(symbol)] = args
}
value = eval(p.body, en)
default:
log.Println("Unknown procedure type - APPLY", p)
}
return
}
type proc struct {
params, body scmer
en *env
}
/*
Environments
*/
type vars map[symbol]scmer
type env struct {
vars
outer *env
}
func (e *env) Find(s symbol) *env {
if _, ok := e.vars[s]; ok {
return e
} else {
return e.outer.Find(s)
}
}
/*
Primitives
*/
var globalenv env
func init() {
globalenv = env{
vars{ //aka an incomplete set of compiled-in functions
"+": func(a ...scmer) scmer {
v := a[0].(number)
for _, i := range a[1:] {
v += i.(number)
}
return v
},
"-": func(a ...scmer) scmer {
v := a[0].(number)
for _, i := range a[1:] {
v -= i.(number)
}
return v
},
"*": func(a ...scmer) scmer {
v := a[0].(number)
for _, i := range a[1:] {
v *= i.(number)
}
return v
},
"/": func(a ...scmer) scmer {
v := a[0].(number)
for _, i := range a[1:] {
v /= i.(number)
}
return v
},
"<=": func(a ...scmer) scmer {
return a[0].(number) <= a[1].(number)
},
"equal?": func(a ...scmer) scmer {
return reflect.DeepEqual(a[0], a[1])
},
"cons": func(a ...scmer) scmer {
switch car := a[0]; cdr := a[1].(type) {
case []scmer:
return append([]scmer{car}, cdr...)
default:
return []scmer{car, cdr}
}
},
"car": func(a ...scmer) scmer {
return a[0].([]scmer)[0]
},
"cdr": func(a ...scmer) scmer {
return a[0].([]scmer)[1:]
},
"list": eval(read(
"(lambda z z)"),
&globalenv),
},
nil}
}
/*
Parsing
*/
//symbols, numbers, expressions, procedures, lists, ... all implement this interface, which enables passing them along in the interpreter
type scmer interface{}
type symbol string //symbols are represented by strings
type number float64 //numbers by float64
func read(s string) (expression scmer) {
tokens := tokenize(s)
return readFrom(&tokens)
}
//Syntactic Analysis
func readFrom(tokens *[]string) (expression scmer) {
//pop first element from tokens
token := (*tokens)[0]
*tokens = (*tokens)[1:]
switch token {
case "(": //a list begins
L := make([]scmer, 0)
for (*tokens)[0] != ")" {
if i := readFrom(tokens); i != symbol("") {
L = append(L, i)
}
}
*tokens = (*tokens)[1:]
return L
default: //an atom occurs
if f, err := strconv.ParseFloat(token, 64); err == nil {
return number(f)
} else {
return symbol(token)
}
}
}
//Lexical Analysis
func tokenize(s string) []string {
return strings.Split(
strings.Replace(strings.Replace(s, "(", "( ",
-1), ")", " )",
-1), " ")
}
/*
Interactivity
*/
func String(v scmer) string {
switch v := v.(type) {
case []scmer:
l := make([]string, len(v))
for i, x := range v {
l[i] = String(x)
}
return "(" + strings.Join(l, " ") + ")"
default:
return fmt.Sprint(v)
}
}
func Repl() {
scanner := bufio.NewScanner(os.Stdin)
for fmt.Print("> "); scanner.Scan(); fmt.Print("> ") {
fmt.Println("==>", String(eval(read(scanner.Text()), &globalenv)))
}
}
First one is type switch. You can read about it more here.
Second one is slicing like in python (if you know it, should be familiar)
ls = ls[1:]
We're skipping first item and taking the rest of the slice/list.
As I see from your comments, I think it's not a good starting point to experiment with golang.
e := expression.(type) is a type assertion.
switch p := procedure.(type) { (with the following case statements) is a type switch.
*tokens = (*tokens)[1:] is a slice expression changing the value stored in *tokens.
token := (*tokens)[0] // Set token to first element of tokens slice.
*tokens = (*tokens)[1:] // Update tokens to remove first element.
switch token { // Switch on token.
case "(": //a list begins // If token is "("
L := make([]scmer, 0) // Make a new, empty slice.
for (*tokens)[0] != ")" { // While the first element of tokens is not ")":
// Read from tokens; if not empty symbol:
if i := readFrom(tokens); i != symbol("") {
L = append(L, i) // Add the token read (in i) to L.
}
}
*tokens = (*tokens)[1:] // Remove the first element from tokens.
return L // Return the newly created slice.