How can I access a slice defined inside the struct?
type Car struct {
Year int
Name string
Type []int
}
//Accessing "Type" array field as below causes error: array out of range.
Car.Type[0] = 12
Car.Type[1] = 15
Car.Type[2] = 11
You mistake slice for array. It must be:
type Car struct {
Year int
Name string
Type [3]int // <---
}
See running code
You should read this tour: https://tour.golang.org/moretypes/6
You can't directly access a slice field if it's not been initialised. You're defining a struct to have 3 fields: Year of type int, this is a simple value that is part of the struct. Same goes for Name. The Type field, however, is a slice. A slice is a reference type. That means it's essentially a hidden struct (called the slice header) with underlying pointer to an array that is allocated dynamically for you. This underlying pointer is, at the time you initialise your variable, nil.
type Car struct {
Year int
Name string
Type []int
}
Can be seen as:
type Car struct {
Year int
Name string
Type struct{
type: "int",
array *[]T
}
}
Not exactly, but you get the idea. When you write:
c := Car{}
All you've allocated is the int, string and the slice header. You must, therefore initialise the slice first:
c := Car{
Year: 2018,
Name: "vroom",
Type: []int{
1, 2, 3,
},
}
There are many ways to initialise the slice, of course. You don't have to set the values just yet, but you could, for example, allocate and initialise the memory you need in one go:
c.Type = make([]int, 3) // allocates an initialised 3 elements in the slice to 0
you can also allocate but not initialise the slice by specifying the capacity (this is useful to avoid reallocating and moving the slice around too often):
c.Type = make([]int, 0, 3)
Alternatively, you can have the runtime do it all for you, using append:
c.Type = append(c.Type, 1, 2, 3)
Some examples here
A bit more background. Slices and maps work similarly, broadly speaking. Because they are reference types, that rely on pointers internally, it's possible for functions that have a slice as a return type to return nil for example. This doesn't work for functions returning an int:
func nilSlice() []int {
return nil
}
Because the return type is a slice, what this function will return is, essentially, an empty slice. Accessing it will result in the same error you occurred: index out of range.
Trying to return nil from a function like this won't even compile:
func nilInt() int {
nil
}
The resulting error will say something like "Can't use nil as type int". Treat slices as pointer types: they need to be safely initialised before use. Always check their length, and if you need to optimise, look at how the builtin append function is implemented. It'll just exponentially grow the capacity of the underlying array. Something that you may not always want. It's trivial to optimise this sort of stuff
You are confusing Slices and Array. Slices are like dynamic arrays. The way you have defined the slice, their index is not defined until they are appended. For the above code:
type Car struct {
Type []int
}
var car Car
car.Type = append(car.Type, 12)
car.Type = append(car.Type, 15)
car.Type = append(car.Type, 11)
Also, Car in your case is a type of object not a object itself. I have declared object car of type Car.
Related
First of all, apologies if this question is confused since I'm just trying out Go and have no idea what I'm doing. I have a struct composed of a variety of attributes of different types, example:
type foo struct {
bar string
baz int
bez []string
(...)
Initially I wanted to iterate over all these attributes and print the value if it existed, but I realized you cannot range over a struct the same way you could, say, a list or map. So I've tried out a few tricks with no luck (like trying to iterate over a separate list of attributes), and I think it's better I just ask for help because I'm probably in over my head here.
The idea is that if I create a new instance of this struct, I'd like to be able to then only print values that are set:
obj := foo{"bar_string", 1}
Given that the string slice bez is not set in obj, I'd like to be able to do something like (pseudo):
for i in obj:
print i
Giving:
"bar_string"
1
Ideally, not printing [] which I guess is the zero value for bez.
Am I approaching this whole thing wrong? The reason I'm not using a map is because I'd like the attributes to be different types, and I'd like future differing objects I'm working in to be organized into structs for clarity.
Go doesn't have builtin struct iteration. The for ... range statement is applicable only to:
all entries of an array, slice, string or map, or values received on a channel
or defined types with one of those underlying types (e.g. type Foo []int)
If you want to iterate over a struct known at compile time, you might be better off just accessing fields one by one.
If you want to must iterate over a struct not known at compile time, you can use the reflect package (not recommended):
type Foo struct {
Bar string
Baz int
Quux []int
}
// x := Foo{"bar", 1, nil}
func printAny(x interface{}) {
v := reflect.ValueOf(x)
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
if !reflect.DeepEqual(field.Interface(), reflect.Zero(field.Type()).Interface()) {
fmt.Println(field)
// bar
// 1
}
}
}
...but it's slower and there are some gotchas, for example:
field.Interface() panics if the field is unexported
in the if clause you can't just use the comparison operator == because operands might be not comparable:
you have to make sure that the zero value for field types is what you expect
If your goal is to just print the struct, you can simply implement the Stringer interface, where you can do type-safe checks the way you want without reflect:
type Foo struct {
Bar string
Baz int
Quux []int
}
func (f Foo) String() string {
s := []string{f.Bar, strconv.Itoa(f.Baz)}
if f.Quux != nil {
s = append(s, fmt.Sprintf("%v", f.Quux))
}
return strings.Join(s, "\n")
}
func main() {
fmt.Println(Foo{"bar", 1, nil})
// bar
// 1
}
A Go playground
type Developer struct {
Name string `json:"name"`
Skills []interface{} `json:"skills"`
}
This is my struct
var developers []Developer
var devData Developer
if searchResult.TotalHits() > 0 {
for _, hit := range searchResult.Hits.Hits {
err := json.Unmarshal(hit.Source, &devData)
if err != nil {
fmt.Println("error")
}
fmt.Println(devData.Skills) // utp here data are correct
developers = append(developers, devData)
}
//after loop data skills value are not correct
}
but when actual data is made the skills are same throught all arrays
expected : ['name' : 'John Doe','skills': ["php","go"]], ['name' : 'Rovvie Doe','skills': ["java","haskel]]
But output : ['name' : 'John Doe','skills': ["java","haskel"]], ['name' : 'Rovvie Doe','skills': ["java","haskel]]
You're reusing the same devData variable, and therefore its allocated memory, in each iteration of the for loop. This means that when you call json.Unmarshal and pass it the pointer to devData you're overwriting what has been written to that memory during the previous iteration.
Instead of declaring the devData variable above the if statment, you should declare it inside the for loop to get a new segment of memory allocated for each of your iteration variables.
Note that if the type of the variable is pointer-less then you could use your original approach since Go is pass-by-value and each time you pass a variable to a function, including append, a shallow copy of that variable's value gets created.
However, since slices in go do hold a pointer to the first element of the slice the Developer type, because of its Skills field, does not qualify.
And that is why you're seeing the Name field getting copied correctly, but the contents of the Skills field getting overwritten.
I realize there are a million variations of the "how do I convert char[]/char* to a Swift Sting" question out there, and their inverse, all of which have been asked and answered.
I'm not asking that.
All I want to do, in Swift, is to simply pass the address of a C char array (obtained via a C function) to the C char* pointer argument of another C function.
Specifically, I'm trying to replicate the following C code, where the address of the char array contained in the stat.f_mntonname field gets passed as the first parameter of getattrlist(const char*, ...) call:
// Get volume stat
const char* path = ...;
struct statfs volStat;
if (statfs(path,&volStat)==-1) { error }
// statfs has the mount point of the volume; use that to get attributes
struct attrlist request;
// ... set up request here
struct volAttrs {
// ... response values
}
if (getattrlist(volStat.f_mntonname,&request,&volAttrs,sizeof(volAttrs),FSOPT_NOFOLLOW)==-1) { error }
The problem seems to be that Swift interprets the stat.f_mntonname field, not as an array, but as a tuple containing MAXPATHLEN number of Int8 values; in other words, (Int8,Int8,Int8,Int8,Int8,...,Int8).
After much poking around on the internet, I was ultimately able to find this workaround:
var volStat = statfs()
guard statfs(fileURL.path, &volStat) != -1 else {
ErrorExit(cause: "statfs")
}
var attrRequest = attrlist()
// set up getattrlist request ...
var attrs = XtraVolumeAttrs()
guard getattrlist(UnsafeRawPointer(&volStat.f_mntonname.0).bindMemory(to: CChar.self, capacity: Int(MAXPATHLEN)),
&attrRequest,
&attrs,
MemoryLayout<XtraVolumeAttrs>.size,
UInt32(FSOPT_NOFOLLOW)) != -1 else {
ErrorExit(cause: "getattrlist")
}
So the magic UnsafeRawPointer(&volStat.f_mntonname.0).bindMemory(to: CChar.self, capacity: Int(MAXPATHLEN) seems to accomplish the task of casting the char[MAXPATHLEN] array into a char*, but boy is it ugly, unintuitive, and—if I'm being completely honest—I'm not even sure this is correct (other than the fact that the code works).
I feel there's got to be a better way and I was hoping someone would post it.
It is ugly because Swift imports C arrays as tuples, and there is no automatic conversion to arrays or pointers.
As pointed out by Hamish, the use of UnsafeRawPointer(&volStat.f_mntonname.0) is incorrect, because the created pointer might be invalid on return from the initializer.
A safe version is
let retval = withUnsafeBytes(of: volStat.f_mntonname) {
getattrlist($0.bindMemory(to: Int8.self).baseAddress, /* other args */)
}
Here bindMemory() is called on the “buffer pointer” covering the raw bytes of the tuple, so that we don't have to specify the capacity explicitly.
I would like to work in Ceylon with a multidimensional array. Is this planned in Ceylon? If so, how can I declare it?
I would like to use this construct in Ceylon, as shown here in Java:
int x = 5;
int y = 5;
String[][] myStringArray = new String [x][y];
myStringArray[2][2] = "a string";
First, consider whether you really need an array (i.e. something with fixed length and modifiable elements), or whether a list (or list of lists) or a map might be better. Though from your example, you seem to need modification.
In the JVM, a "multidimensional" array is just an array of arrays.
In Java, new String[y] creates an array filled with null entries, which is not an allowed value of type String in Ceylon. So you can either have an array of String? (which allows null), or pre-fill your array with some other value, using e.g. Array.ofSize(...):
Array.ofSize(y, "hello")
The same is valid for arrays of arrays. We could do this:
value myStringArray = Array.ofSize(x, Array.ofSize(y, "hello"));
Though this would have the same array in each "row" of the 2D-array, which is not what we want (as replacing myStringArray[2][2] would replace all entries with a 2 as the second coordinate). Here the other Array constructor is useful, which takes an iterable:
value myStringArray = Array({ Array.ofSize(y, "hello") }.repeat(x));
This takes advantage of the fact that the iterable enumeration evaluates its arguments lazily, and thus the array constructor will get x different elements.
I like Paulo's answer, but here's an alternative approach, which allows us to use a comprehension to populate the 2D array:
//the size of the square 2D array
value n = 5;
//create it using a nested comprehension
value arr = Array {
for (i in 1..n-1) Array {
for (j in 0..n-1)
i==j then 1 else 0
}
};
//display it
for (row in arr) {
printAll(row);
}
How do I create an array, which has a set size, that is not known at compile time, but has unset values?
Essentially I want something like int immutable([length]);. length is not known at compile time. Obviously that doesn't compile though.
It'd have to be user-defined. The built-in arrays in D are either static, needed to be known at compile time, or slices into a dynamic array, which can be resized.
Built-in options:
int length = 100;
int[] int_array = new int[length]; // works, contents will be initialized to zero
That's the same as:
int[] int_array;
int_array.length = length;
You can also do immutable(int)[] if you want that, though then you won't be able to set the contents... the normal way to do this would be to write a pure function that creates and sets contents in a mutable array, then returns it:
pure int[] make_array(int length) {
int[] array;
array.length = length;
foreach(i, ref item; array)
item = i; // initialize it to a simple count
return array;
}
// usage:
immutable(int)[] arr = make_array(100); // works
immutable(int[]) iarr = make_array(100); // also works
Mutable data returned from a pure function is the exception to the general prohibition of implicit casting to imuutable: since it comes from a pure function, the compiler knows it is a unique reference, and safe to treat as immutable upon request.
The difference between the first and second line of usage is the first one can be reassigned: arr = something_else[]; /* cool */ whereas the second one cannot be changed at all. No length change, no contents change, no reassignment.
Static arrays are an option, but the length needs to be known at compile time:
int[100] int_array = void; // works, contents uninitialized, non-resizable, but length must be known at compile time
One possible strategy there is to declare a big int_array_buffer, then set int_array = int_array_buffer[0 .. length]. Though, still, int_array will be resizable itself.
To get everything you want, it'll have to be a user-defined type. Something alone these lines could work:
struct MyArray(T) {
#disable this(); // disallow default construction; force a length
// this constructor takes a runtime length and allocates the backing
this(size_t length) { backing = new T[length]; }
private T[] backing = void; // actually holds the data, uninitialized
T[] opSlice() { return backing; } // allow easy conversion to a slice
alias opSlice this; // implicit conversion to slice
}
When passing it to a function, you can pass MyArray!int, or a plain int[]. Thanks to the alias this, it will implicitly convert to int[], and thanks to the D slicing rules, even if the slice is resized in that function, it won't affect your MyArray instance.
Let's look at some usage:
void main() {
int length = 100; // runtime
// MyArray!int uninitialized; // compile error thanks to #disable this
MyArray!int uninitialized = void; // ok, explicitly uninitialized
uninitialized = MyArray!int(length); // created
// or
auto my_array = MyArray!int(length); // also creates it
// my_array.length = 20; // compile error "my_array.opSlice().length is not an lvalue" - it is not resizable
// my_array ~= 1; // compile again, "cannot append type int to type MyArray!int" - again because it is not resizable
int[] slice = my_array; // works, makes passing it to functions that expect normal arrays easy
}
That should give you everything you need. With wrapper structs in D, you can selectively enable and disable functionality of the underlying type with no loss in efficiency.
No need for a wrapper (unless I misunderstood). Just use the allocation primitives in http://dlang.org/phobos/core_memory.html. You can get a chunk of memory that's essentially an uninitialized array of anything you wish.