I'm new to Go and I'm trying to learn it by making a repost bot. Anyway, I'm having a problem that I don't know how to solve exactly.
I have the following Struct:
type Post struct {
Title string
Url string
}
And I'm trying to get these values using goQuery, like this:
var title = doc.Find(".title.title.may-blank").Each(func(i int, s *goquery.Selection) {
fmt.Println("Title:", s.Text())
})
But when I try to set the value to the Post struct, I get this error:
cannot use title (type *goQuery.Selection) as type string in field value.
Ok, that makes sense, but how can I cast it to string? I've tried s.Text() but it doesn't works. I thought about making a function that returns a string, but I'm not sure if this would work.
I'll appreciate if someone can help me, thanks in advance!
The issue is that .Each returns the original *goquery.Selection so that you can chain calls. If you need to get the string value, you just assign it directly, like this:
var title string
doc.Find(".title.title.may-blank").Each(func(i int, s *goquery.Selection) {
title = s.Text()
})
Related
In Go is there a good way to use reflection to get a field tag by just wrapping a field in a function from the reflect library?
I am basically trying to create a thin data access object that allows be to get the column name in the db without hard coding it all over the place.
Below is the struct with db column names as tags.
// Table Structures
type CusipTableRow struct {
Id int64 `db:"id"`
Cusip string `db:"cusip"`
Symbol string `db:"symbol"`
Active int8 `db:"active"`
Added_Time int32 `db:"added_timestamp"`
Description string `db:"description"`
Exchange string `db:"exchange"`
AssetType string `db:"asset_type"`
}
I am seeking a suggestion other than downloading another library on how to use reflection to essentially make a call like this to return a string with the tag value.
var row CusipTableRow
row.GetColumnName(row.Id) //Return column name based on tag.
I was considering possibly trying to use a map[address] fieldTag, but did not have luck getting that to work perhaps due to not fully having a grasp of the unsafe package. If that approach would have worked I was thinking a call like this could have worked:
row.GetColumnName(&row.Id) //Return column name based on tag.
You can get field tag given the address of the struct and the address of the field. Unsafe shenanigans are not required.
func GetColumnName(pstruct interface{}, pfield interface{}) string {
v := reflect.ValueOf(pstruct).Elem()
for i := 0; i < v.NumField(); i++ {
if v.Field(i).Addr().Interface() == pfield {
return v.Type().Field(i).Tag.Get("db")
}
}
panic("field not in struct")
}
Example use:
var v CusipTableRow
fmt.Println(GetColumnName(&v, &v.Added_Time)) // prints added_timestamp
Run it on the Go Playground.
I would like to set a default value and if this is not set in a structure, I would like to set it. It's a bit confusing, but please take a look to the (simplified) code:
package main
import "log"
type Something struct {
A string
B map[string]Type
C Epyt
}
type Type struct {
A Epyt
B string
}
type Epyt struct {
A string
B string
}
func main() {
var a Something
a.A = "Test A (Something)"
// var a.B["one"] Type
a.B["one"].A.A = a.B["one"].A.A
a.B["one"].A.A = "Test A ([one]Type.Epyt)"
a.B["two"].A.A = "Test A ([two]Type.Epyt)"
a.C.A = "Test A (Epyt)"
a.C.B = "Test B (Epyt)"
for i := range a.B {
if a.B[i].A.B == "" {
a.B[i].A.B = a.C.B
}
}
log.Printf("%+v", a)
}
I'm working with viper to unmarshal a config file, therefor I'm not able to use pointers (or am I wrong?).
The error I'm getting, is cannot assign to struct field *** in map.
I found that this is an old bug in go lang still not corrected.
I've read Why do I get a "cannot assign" error when setting value to a struct as a value in a map? and Golang: I have a map of structs. Why can't I directly modify a field in a struct value? but as I said, I can't operate with pointers (or?), therefor please don't mark this as duplicate as it is not!
If someone has an idea on how to do this right, please help!
I played around a bit and got it working! I thought there is an error, because if I use printf over the whole structure, I get the address instead of the value back. Sorry for the inconvenience!
As #mkopriva told me, I tried to use pointers. After some errors I got it to work so far! Sorted out this brain bug ;)
Thank you again!
You haven't initialised the map.
Try
var a Something
a.B = make(map[string]Type)
Also, none of the structures you're referring to exist.
Ie, instead of:
a.B["one"].A.A = ...
You should do:
a.B["one"] = Type{
A: Epyt{
A: "test",
B: "foo",
},
B: "something",
}
I'm finding the use of the blank identifier a little hard to understand. I've looked at effective go and understand most of the use cases they describe but then looking at a tutorial I came across this in a route handler function:
var person Person
_ = json.NewDecoder(req.Body).Decode(&person)
in the first line we create a new empty variable of type Person (a struct previously defined) and then I assume that
&person is passing the person var in by reference,
to be filled with data by the Decode function
this function then goes on to perform a few more tasks before encoding and returning a json response.
Why do we need have the decode assigned to a blank identifier? Couldn't we just run json.NewDecoder(req.Body).Decode(&person) ? if we can't, why not?
I'm assuming you're learning golang and asking because you can't identify why this example used this practice.
As #JimB mentioned in comments, the example writer didn't need to do this they're simply ignoring the Error return.
The blank identifier _ can be used to strictly provide the keys in a struct too. See this for reference
Without enforcing
type SomeStruct struct {
FirstField string
SecondField bool
}
myStruct := SomeStruct{"", false}
Enforcing to mention the key for the value (Removes the dependency of ordering the values)
type SomeSturct struct {
FirstField string
SecondField bool
_ struct{}
}
// COMPILATION ERROR
myStruct := SomeSturct{"", false}
The above will give the error too few values in SomeSturct literal
If I have a struct like this:
type Message struct {
Id int64
Message string
ReplyTo *int64
}
And then if I did create an instance of this struct like this:
var m Message
m.Id = 1
m.Message = "foo bar yo"
var replyTo = int64(64)
m.ReplyTo = &replyTo
Then it would work.
But I was wondering if there was a shortcut for the last step?
I tried doing something like:
m.ReplyTo = &int64{64}
But it did not work.
I don't think you can because the value is a primitive and attempting to do it in one shot like the below would be a syntax error. Its attempting to get an address of a value so it wouldn't be possible. At least I am not aware of a way where its possible.
someInt := &int64(10) // would not compile
The other alternative you have is to write a function to return a pointer to the primitive like the following:
func NewIntPointer(value int) *int {
return &value
}
A tricky way to get int pointer without create new variable.
someIntPtr := &[]int64{10}[0]
In Golang, is there an easy way to print for debugging the dereferenced pointers given a slice of pointers to structs?
If you don't want to use unsafe and an external package.. you can range over it yourself:
for _, p := range people {
fmt.Printf("%+v\n", p)
}
Output:
&{name:Simon age:25}
&{name:Bob age:31}
Working sample: http://play.golang.org/p/aVw0rhQNuk
Maybe it's a late answer, but I've just come across the same problem and wanna save my choice here for anyone needed.
I added a String() function to my item type. For example:
type SliceItem struct {
ID int32
Name string
}
func (i *SliceItem) String() string {
return fmt.Sprintf("id = %d, name = %s\n", i.ID, i.Name)
}
As a result, whenever I wanna print this item, I got friendly "id = xx, name = xxx" string, instead of unreadable pointer addresses.
If you want to print individual elements, try it with the index and asterix for dereferencing:
fmt.Println(*pointer_strcut_slice[0])
fmt.Println(*pointer_strcut_slice[1])