I am trying to modify slice a slice in another function, using the following code:
type DT struct {
name string
number int
}
func slicer(a *[]DT) {
tmp := *a
var b []DT
b = append(b, tmp[:1], tmp[2:])
*a = b
}
func main() {
o1 := DT {
name: "name-1",
number: 1,
}
o2 := DT {
name: "name-2",
number: 2,
}
o3 := DT {
name: "name-3",
number: 3,
}
b := make([]DT, 0)
b = append(b, o1)
b = append(b, o2)
b = append(b, o3)
slicer(&b)
fmt.Println(b)
}
What I want is, 1st and last element of the slice. But, in doing so, I am getting following error:
cannot use tmp[:1] (type []DT) as type DT in append
I am relatively new to Go Language, so kindly guide me through this one!
You should use operator ... to convert slice into list of variadic arguments.
b = append(b, tmp[:1]...)
b = append(b, tmp[2:]...)
Related
i want to pass field as parameter to return value from function
package main
import (
"fmt"
)
type s struct {
a int
b int
}
func c(s s) int {
var t int
t = s.a // how to change this to t=s.b just by pass parameter
return t
}
func main() {
fmt.Println(c(s{5, 8}))
}
some times i want to make t = s.a and other time i wanted t = s.b to return value 8 the question is how to pass it like parameter
https://play.golang.org/p/JisnrTxF2EY
You may add a 2nd parameter to signal which field you want, for example:
func c2(s s, field int) int {
var t int
switch field {
case 0:
t = s.a
case 1:
t = s.b
}
return t
}
Or a more convenient way is to pass the name of the field, and use reflection to get that field:
func c3(s s, fieldName string) int {
var t int
t = int(reflect.ValueOf(s).FieldByName(fieldName).Int())
return t
}
Or you may pass the address of the field, and assign the pointed value:
func c4(f *int) int {
var t int
t = *f
return t
}
Testing the above solutions:
x := s{5, 8}
fmt.Println("c2 with a:", c2(x, 0))
fmt.Println("c2 with b:", c2(x, 1))
fmt.Println("c3 with a:", c3(x, "a"))
fmt.Println("c3 with b:", c3(x, "b"))
fmt.Println("c4 with a:", c4(&x.a))
fmt.Println("c4 with b:", c4(&x.b))
Which will output (try it on the Go Playground):
c2 with a: 5
c2 with b: 8
c3 with a: 5
c3 with b: 8
c4 with a: 5
c4 with b: 8
I faced such a problem.
I need to compare two structure if they type and name of field is equal.
To assign value from sour to dist. I write some code, but here I can assign reflect.Field() value. Could you help me? And I create the test in the bellow
import (
"reflect"
"testing"
)
func Assign(sour interface{}, dist interface{}) uint {
counter := 0
source := reflect.ValueOf(sour)
target := reflect.ValueOf(dist)
typeSource := reflect.TypeOf(sour)
typeTarget := reflect.TypeOf(dist)
for i:=0; i<source.NumField(); i++{
for j:=0; j<target.NumField();j++{
if (typeSource.Field(i).Type==typeTarget.Field(j).Type && typeSource.Field(i).Name==typeTarget.Field(j).Name){
counter = counter + 1
target.FieldByName(typeSource.Field(i).Name).Set(source.Field(i))
}
}
}
return uint(counter)
}
func TestAssign(t *testing.T) {
type A struct {
A string
B uint
C string
}
type B struct {
AA string
B int
C string
}
var (
a = A{
A: "Тест A",
B: 55,
C: "Test C",
}
b = B{
AA: "OKOK",
B: 10,
C: "FAFA",
}
)
result := Assign(a, b)
switch true {
case b.B != 10:
t.Errorf("b.B = %d; need to be 10", b.B)
case b.C != "Test C":
t.Errorf("b.C = %v; need to be 'Test C'", b.C)
case result != 1:
t.Errorf("Assign(a,b) = %d; need to be 1", result)
}
}
For Assign to work, the second argument must be addressable, i.e. you need to pass a pointer to the struct value.
// the second argument MUST be a pointer to the struct
Assing(source, &target)
Then you need to slightly modify your implementation of Assign since a pointer does not have fileds. You can use the Elem() method to get the struct value to which the pointer points.
func Assign(sour interface{}, dist interface{}) uint {
counter := 0
source := reflect.ValueOf(sour)
// dist is expected to be a pointer, so use Elem() to
// get the type of the value to which the pointer points
target := reflect.ValueOf(dist).Elem()
typeSource := reflect.TypeOf(sour)
typeTarget := target.Type()
for i := 0; i < source.NumField(); i++ {
for j := 0; j < target.NumField(); j++ {
if typeSource.Field(i).Type == typeTarget.Field(j).Type && typeSource.Field(i).Name == typeTarget.Field(j).Name {
counter = counter + 1
target.FieldByName(typeSource.Field(i).Name).Set(source.Field(i))
}
}
}
return uint(counter)
}
I have an enum in a proto file that generates to integer constants in the pb.go file. I now have some integers coming from the an external data source and want to safely map them to the possible constants.
Here is what I currently have: https://play.golang.org/p/-5VZqPbukd
package main
import (
"errors"
"fmt"
)
//enum in the proto file
//
// enum X {
// A = 0;
// B = 1;
// C = 2;
// D = 3;
// }
//enum type generated by protoc
type X int32
//enum constants generated by protoc
const (
X_A X = 0
X_B X = 1
X_C X = 2
X_D X = 3
)
func intToX(v int) (X, error) {
x := X(v)
switch x {
case X_A, X_B, X_C, X_D:
return x, nil
}
return 0, errors.New("could not convert int to X")
}
func main() {
for i := -1; i < 10; i++ {
if x, err := intToX(i); err != nil {
fmt.Println("unhandled error:", err, "for input value", i)
} else {
fmt.Printf("%d => X(%d)\n", i, x)
}
}
}
Question: Is there a better, more idiomatic way to map incoming integer values to protoc-generated constants?
In particular, I would like to avoid listing all constants explicitly in the case A, B, C, D statement.
I do not know which proto generation package you are using, but with github.com/golang/protobuf/proto you also get the reverse mapping of enums.
Example xyz.pb.go generated file:
type TimeInterval int32
const (
TimeInterval_TI_UNKNOWN TimeInterval = 0
TimeInterval_TI_HOUR TimeInterval = 1
TimeInterval_TI_DAY TimeInterval = 2
TimeInterval_TI_WEEK TimeInterval = 3
TimeInterval_TI_MONTH TimeInterval = 4
TimeInterval_TI_QUARTER TimeInterval = 5
TimeInterval_TI_YEAR TimeInterval = 6
)
var TimeInterval_name = map[int32]string{
0: "TI_UNKNOWN",
1: "TI_HOUR",
2: "TI_DAY",
3: "TI_WEEK",
4: "TI_MONTH",
5: "TI_QUARTER",
6: "TI_YEAR",
}
var TimeInterval_value = map[string]int32{
"TI_UNKNOWN": 0,
"TI_HOUR": 1,
"TI_DAY": 2,
"TI_WEEK": 3,
"TI_MONTH": 4,
"TI_QUARTER": 5,
"TI_YEAR": 6,
}
func (x TimeInterval) String() string {
return proto.EnumName(TimeInterval_name, int32(x))
}
func (TimeInterval) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
So with this you could test for existence in the following manner:
if _, found := TimeInterval_name[testinputint]; found{
//all ok
} else {
//not a value for this enum
}
Yes as #RickyA mentions using a range is nice as it verifies for all the possible underlying const values.
Additionally you could check the length of the enum, although that would only be possible when the underlying enum values do not have any 'gaps' and have a consequitive range of numbers.
Verbose explanation via code:
typelength := int32(len(TimeInterval_name))
if testinputint < 0 || int32(testinputint) >= typelength {
// not a value for this enum, return err
}
A bit less verbose, and just using int instead of int32
if testinputint < 0 || int(testinputint) >= len(TimeInterval_name) {
// not a value for this enum, return err
}
But as said, this will only be valid for enums that adhere to a proper iota. That might not be the case when you have changed your enum to read something like this:
var TimeInterval_name = map[int32]string{
0: "TI_UNKNOWN",
1: "TI_HOUR",
2: "TI_DAY",
3: "TI_WEEK",
// we do not use month anymore 4: "TI_MONTH",
5: "TI_QUARTER",
6: "TI_YEAR",
}
as the length of the generated map will be clearly less than six :)
In other words use the found method of #Ricky_A above to keep on the safe side.
Is it possible to declare multiple variables at once using Golang?
For example in Python you can type this:
a = b = c = 80
and all values will be 80.
Yes, you can:
var a, b, c string
a = "foo"
fmt.Println(a)
You can do something sort of similar for inline assignment, but not quite as convenient:
a, b, c := 80, 80, 80
Another way to do this is like this
var (
a = 12
b = 3
enableFeatureA = false
foo = "bar"
myvar float64
anothervar float64 = 2.4
)
Also works for const
const (
xconst = 5
boolconst = false
)
In terms of language specification, this is because the variables are defined with:
VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
(From "Variable declaration")
A list of identifiers for one type, assigned to one expression or ExpressionList.
const a, b, c = 3, 4, "foo" // a = 3, b = 4, c = "foo", untyped integer and string constants
const u, v float32 = 0, 3 // u = 0.0, v = 3.0
Yes you can and it is slightly more nuanced than it seems.
To start with, you can do something as plain as:
var a, b, x, y int // declares four variables all of type int
You can use the same syntax in function parameter declarations:
func foo(a, b string) { // takes two string parameters a and b
...
}
Then comes the short-hand syntax for declaring and assigning a variable at the same time.
x, y := "Hello", 10 // x is an instance of `string`, y is of type `int`
An oft-encountered pattern in Golang is:
result, err := some_api(...) // declares and sets `result` and `err`
if err != nil {
// ...
return err
}
result1, err := some_other_api(...) // declares and sets `result1`, reassigns `err`
if err != nil {
return err
}
So you can assign to already-defined variables on the left side of the := operator, so long as at least one of the variables being assigned to is new. Otherwise it's not well-formed. This is nifty because it allows us to reuse the same error variable for multiple API calls, instead of having to define a new one for each API call. But guard against inadvertent use of the following:
result, err := some_api(...) // declares and sets `result` and `err`
if err != nil {
// ...
return err
}
if result1, err := some_other_api(...); err != nil { // result1, err are both created afresh,
// visible only in the scope of this block.
// this err shadows err from outer block
return err
}
Several answers are incorrect: they ignore the fact that the OP is asking whether it is possible to set several variables to the same value in one go (sorry for the pun).
In go, it seems you cannot if a, b, c are variables, ie you will have to set each variable individually:
a, b, c := 80, 80, 80
But if a, b, c are constants, you can:
const (
a = 80
b
c
)
Try this in the go-playground:
https://play.golang.org/
package main
import "fmt"
func main() {
a, b := "a", "b"; //Declare And Assign
var c, d string; //Declare Only
fmt.Println(a,b);
fmt.Println(c,d);
}
Another way of doing is using var for package level assignment
package main
import (
"fmt"
)
var (
a, b, c = 80, 80 ,80
)
func main() {
fmt.Println(a, b, c)
}
long declaration
var varName1, varName2 string = "value","value"
short declaration
varName1,varName2 := "value1","value2"
I have a struct A, extending ("subclassing") it with struct B, like this:
package main
type A struct {
x int
}
type B struct {
A
y int
}
I want to create a array where I can append A or B to it, so that this code works:
func main() {
var m [2]B
m[0] = B { A { 1 }, 2 }
m[0].x = 0
m[0].y = 0
m[1] = A { 3 }
m[1].x = 0
}
It doesn't. If I create the array of the type B, I get "cannot use struct literal (type A) as type B in assignment". If I try to create the array of the type A, I get the the same error (just with the types reversed).
So my question is: which type should the array be?
You could use struct values. For example,
package main
import "fmt"
type A struct {
x int
}
type B struct {
A
y int
}
func main() {
var m []interface{}
m = append(m, B{A{1}, 2})
m = append(m, A{3})
fmt.Println(m[0], m[1])
if b, ok := m[0].(B); ok {
b.x = 0
b.y = 0
m[0] = b
}
if a, ok := m[1].(A); ok {
a.x = 0
m[1] = a
}
fmt.Println(m[0], m[1])
}
Output:
{{1} 2} {3}
{{0} 0} {0}
Or, you could use struct pointers. For example,
package main
import "fmt"
type A struct {
x int
}
type B struct {
A
y int
}
func main() {
var m []interface{}
m = append(m, &B{A{1}, 2})
m = append(m, &A{3})
fmt.Println(m[0], m[1])
if b, ok := m[0].(*B); ok {
b.x = 0
b.y = 0
}
if a, ok := m[1].(*A); ok {
a.x = 0
}
fmt.Println(m[0], m[1])
}
Output:
&{{1} 2} &{3}
&{{0} 0} &{0}
You'll want to define the array type to interface{} rather than B. Then you can store both types in there. That's the only way to accomplish this. If both types implement a specific interface, then you can type to that instead of the generic interface{}