Is there some way to resolve C struct dynamically in Go? - go

I defined a struct in C like:
struct SomeStruct
{
int var1;
bool var2;
double var3;
int var4[10];
int var5[10][10];
}
struct SomeStruct entity;
And somewhere there was a input box that some user input in GO:
func("entity.var3")
It will return value of entity.var3 in C struct.
Actually I could already implement it in python by cffi and:
def get_one_variable(buffer, setup):
value = buffer
for level in setup:
if isinstance(level, str):
value = getattr(value, level)
else:
[base, extends] = level
value = getattr(value, base)
for extend in extends:
value = value[extend]
return value
Where buffer is python cffi data pointer defined with "FFI.cdef" and setup resolved by:
def parse_variable(self, line):
line = line.replace('\n', '').replace(' ', '')
split = line.split('.')
variable = []
for child in split:
match = self.BASE_EXT_REGEX.match(child)
if match is None:
variable.append(child)
else:
base_name = match.group('base_name')
ext_name = match.group('ext_name')
variable.append([base_name, [int(index) for index in
ext_name.replace('[', ']').replace(']]', ']').strip(']').split(']')]])
return variable
So I can dynamically resolve "entity.var1", "entity.var2", "entity.var3", "entity.var4[0]", "entity.var5[0][1]".
Is there something or someway similar in GO?

This is handled by CGO which is a special package in Go that allows for easy C integration. You can read more about it here and here. Given your examples, a simple CGO example would be:
/*
struct SomeStruct
{
int var1;
bool var2;
double var3;
int var4[10];
int var5[10][10];
}
*/
import "C"
import "fmt"
func main(){
thing := C.struct_SomeStruct{}
thing.var1 = C.int(5)
fmt.Printf("My Struct's var field %d\n",int(thing.var1))
}

Related

Zero out anonymous global struct

I have following code
package main
import (
"fmt"
)
var dog struct {
Name string
Age int
Breed string
}
func main() {
dog.Name = "Pongo"
dog.Age = 7
dog.Breed = "Dalmatian"
fmt.Println(dog)
// Reset struct.
dog{} --- Problem point with error
fmt.Println(dog)
dog.Name = "Fluffy"
dog.Breed = "Poodle"
fmt.Println(dog)
}
I am trying to clear out the global struct in Reset.
I know I can do it individually. I am looking into golang way of doing like we can do it for struct as follow
type Dog struct {
Name string
Age int
Breed string
}
dog = Dog {}
If you have a variable of struct type, you may zero it by assigning the zero value of its type.
As noted by others, since you have a variable of anonymous type, the composite literal has to repeat the struct definition:
// Reset with struct literal:
dog = struct {
Name string
Age int
Breed string
}{}
This is inconvenient. So just use a named type.
You could also do it with reflection:
// Reset using reflection:
p := &dog
v := reflect.ValueOf(p).Elem()
v.Set(reflect.New(v.Type()).Elem())
The advantage here is that we didn't have to repeat the struct definition, and this solution works with all structs (and other types too). But using reflection is slower. Again, just use a named type.
You may try the examples on the Go Playground.
What's wrong with the solution you proposed? That is how you would do it:
package main
import (
"fmt"
)
type Dog struct {
Name string
Age int
Breed string
}
var dog = Dog{}
func main() {
dog.Name = "Pongo"
dog.Age = 7
dog.Breed = "Dalmatian"
fmt.Println(dog)
// Reset struct.
dog = Dog{}
fmt.Println(dog)
dog.Name = "Fluffy"
dog.Breed = "Poodle"
fmt.Println(dog)
}

int data type in Go

I am new to Go language and was trying out few examples in GO.
In GO int is not a keyword so I declared a variable with name as int.
package main
import "fmt"
func main() {
var int int = 8
fmt.Println(int)
var number int = 10
fmt.Println(number)
}
Now when I build this code I get following error:
[dev#go test]$ go build variables.go
# command-line-arguments
./variables.go:8: int is not a type
I am trying to understand the reason why this is seen and what did var int int do such that int becomes an unavailable data type.
package main
import "fmt"
func main() {
// int is a predeclared type identifier
var int int = 8
// int is a variable identifier
fmt.Println(int)
// error: int is not a type
var number int = 10
fmt.Println(number)
}
You are shadowing the int identifier.
See The Go Programming Language Specification.
Go is a block structured programming language:
Blocks
Declarations and scope
int is a predeclared identifier and is implicitly declared in the universe block.
The scope of a variable identifier declared inside a function begins at the end of the declaration and ends at the end of the innermost containing block.
The statement
var int int = 8
uses the predeclared int type to declare a variable identifier int, shadowing the predeclared identifier: Variable shadowing.
In Go int is a predefined identifier, therefore it cannot be used as a variable name. So rename the first variable to anything else. Such as num1 and it will compile!
package main
import "fmt"
func main() {
var num1 int = 8
fmt.Println(num1)
var number int = 10
fmt.Println(number)
}
Hope this helps!

How to declare variable types for loop variables in Go?

See this code.
package main
import (
"fmt"
)
func main() {
var arr [4]string = [4]string{"foo", "bar", "baz", "qux"}
for a, b := range arr {
fmt.Println(a, b)
}
// How can I fix this code?
/*
for x int, y string = range arr {
fmt.Println(a, b)
}
*/
}
The first for loop uses the := operator to automatically deduce the types of a and b. But what if I want to explicitly specify the types of the loop variables? My attempt to do this is in the second block of commented code which of course failed with the following error.
# command-line-arguments
./foo.go:15: syntax error: unexpected name, expecting {
./foo.go:18: syntax error: unexpected }
Can you help me fix the second block of code such that I can specify the types of x and y explicitly?
Unfortunately the language specification doesn't allow you to declare the variable type in the for loop. The closest you could get is this:
var a int
var b string
for a, b = range arr {
fmt.Println(a, b)
}
But normally if you give your variable meaningful names, their type would be clear as well:
for index, element := range arr {
fmt.Println(index, element)
}
You need to declare first the vars.
var x int
var y string ...// now it should be ok.
for x,y = range arr {
fmt.Println(x, y) // it should be x and y instead of a,b
}
Check the fiddle
First of all your code is not a valid Go code. The for range loop returns the index and the value of an array, slice, string, or map, so there is no reason the explicitly specify the type of the value and the index.
You are specifying the type of the values at the variable initialization, and the language will deduce the type on the range iteration.
One special case is when you are using interface{} as variable type. In this case, you if you need to know the type of the value you can use the reflect package to deduce the type of the value.
switch reflect.TypeOf(t).Kind() {
case reflect.Slice:
s := reflect.ValueOf(t)
for i := 0; i < s.Len(); i++ {
fmt.Println(s.Index(i))
}
}
It's not possible as you are trying to declare two different types of data in same line, if you want explicitly declare variables, then you need to declare them before itself like above answers, but if you want them to be of other type then you need to covert them as for your needs,
package main
import (
"fmt"
)
func main() {
var arr = [4]string{"foo", "bar", "baz", "qux"}
var x int64
var b []byte
for x = 0; x < int64(len(arr)); x++ {
b = []byte(arr[x])
fmt.Println(x, b)
}
}

How to assert ast.TypeSpec to int type in Golang?

I have following code for Golang docs parsing. "ts" is ast.TypeSpec. I can check StructType and etc. But, ts.Type is "int". How can I assert for int and other basic type?
ts, ok := d.Decl.(*ast.TypeSpec)
switch ts.Type.(type) {
case *ast.StructType:
fmt.Println("StructType")
case *ast.ArrayType:
fmt.Println("ArrayType")
case *ast.InterfaceType:
fmt.Println("InterfaceType")
case *ast.MapType:
fmt.Println("MapType")
}
The types in the AST represent the syntax used to declare the type and not the actual type. For example:
type t struct { }
var a int // TypeSpec.Type is *ast.Ident
var b struct { } // TypeSpec.Type is *ast.StructType
var c t // TypeSpec.Type is *ast.Ident, but c variable is a struct type
I find it's helpful to print example ASTs when trying to understand how different syntax is represented. Run this program to see an example.
This code will check for ints in most cases, but does not do so reliably:
if id, ok := ts.Type.(*ast.Ident); ok {
if id.Name == "int" {
// it might be an int
}
}
The code is not correct for the following cases:
type myint int
var a myint // the underlying type of a is int, but it's not declared as int
type int anotherType
var b int // b is anotherType, not the predeclared int type
To reliably find the actual types in the source, use the go/types package. A tutorial on the package is available.

Using reflect, how do you set the value of a struct field?

having a rough time working with struct fields using reflect package. in particular, have not figured out how to set the field value.
type t struct { fi int; fs string }
var r t = t{ 123, "jblow" }
var i64 int64 = 456
getting Name of field i - this seems to work
var field = reflect.TypeOf(r).Field(i).Name
getting value of field i as a) interface{}, b) int - this seems to work
var iface interface{} = reflect.ValueOf(r).Field(i).Interface()
var i int = int(reflect.ValueOf(r).Field(i).Int())
setting value of field i - try one - panic
reflect.ValueOf(r).Field(i).SetInt( i64 )
panic: reflect.Value·SetInt using value obtained using unexported field
assuming it did not like field names "id" and "name", so renamed to "Id" and "Name"
a) is this assumption correct?
b) if correct, thought not necessary since in same file / package
setting value of field i - try two (with field names capitalized ) - panic
reflect.ValueOf(r).Field(i).SetInt( 465 )
reflect.ValueOf(r).Field(i).SetInt( i64 )
panic: reflect.Value·SetInt using unaddressable value
Instructions below by #peterSO are thorough and high quality
Four. this works:
reflect.ValueOf(&r).Elem().Field(i).SetInt( i64 )
he documents as well that the field names must be exportable (begin with capital letter)
The Go json package marshals and unmarshals JSON from and to Go structures.
Here's a step-by-step example which sets the value of a struct field while carefully avoiding errors.
The Go reflect package has a CanAddr function.
func (v Value) CanAddr() bool
CanAddr returns true if the value's
address can be obtained with Addr.
Such values are called addressable. A
value is addressable if it is an
element of a slice, an element of an
addressable array, a field of an
addressable struct, or the result of
dereferencing a pointer. If CanAddr
returns false, calling Addr will
panic.
The Go reflect package has a CanSet function, which, if true, implies that CanAddr is also true.
func (v Value) CanSet() bool
CanSet returns true if the value of v
can be changed. A Value can be changed
only if it is addressable and was not
obtained by the use of unexported
struct fields. If CanSet returns
false, calling Set or any
type-specific setter (e.g., SetBool,
SetInt64) will panic.
We need to make sure we can Set the struct field. For example,
package main
import (
"fmt"
"reflect"
)
func main() {
type t struct {
N int
}
var n = t{42}
// N at start
fmt.Println(n.N)
// pointer to struct - addressable
ps := reflect.ValueOf(&n)
// struct
s := ps.Elem()
if s.Kind() == reflect.Struct {
// exported field
f := s.FieldByName("N")
if f.IsValid() {
// A Value can be changed only if it is
// addressable and was not obtained by
// the use of unexported struct fields.
if f.CanSet() {
// change value of N
if f.Kind() == reflect.Int {
x := int64(7)
if !f.OverflowInt(x) {
f.SetInt(x)
}
}
}
}
}
// N at end
fmt.Println(n.N)
}
Output:
42
7
If we can be certain that all the error checks are unnecessary, the example simplifies to,
package main
import (
"fmt"
"reflect"
)
func main() {
type t struct {
N int
}
var n = t{42}
fmt.Println(n.N)
reflect.ValueOf(&n).Elem().FieldByName("N").SetInt(7)
fmt.Println(n.N)
}
BTW, Go is available as open source code. A good way to learn about reflection is to see how the core Go developers use it. For example, the Go fmt and json packages. The package documentation has links to the source code files under the heading Package files.
This seems to work:
package main
import (
"fmt"
"reflect"
)
type Foo struct {
Number int
Text string
}
func main() {
foo := Foo{123, "Hello"}
fmt.Println(int(reflect.ValueOf(foo).Field(0).Int()))
reflect.ValueOf(&foo).Elem().Field(0).SetInt(321)
fmt.Println(int(reflect.ValueOf(foo).Field(0).Int()))
}
Prints:
123
321

Resources