I have this code in which I am appending to an array of a struct in one function. The change does not appear in the other function.
type my struct{
arr []int
}
func New_my() *my {
m := new (my)
return m
}
func (m my) Dosomething(){
m.arr = append(m.arr,1)
m.arr = append(m.arr,2)
m.arr = append(m.arr,3)
}
func (m my) Dosomethingelse(){
fmt.Println(m.arr)
}
func main(){
m:= New_my()
m.Dosomething()
m.Dosomethingelse()
}
The output is:
[]
Please, explain what is happening? Why does the change not appear in the array?
If you are new to go you should totally do the tour of go and the effective go document. Go is a new language and with a strange combination of ideas so the official documentation is the best place to start.
First of all you are using a slice not an array. (Read this to understand slices)
The error in your code is because Dosomething() is defined for my instead of *my. This is explained here.
Just change it to:
func (m *my) Dosomething(){
m.arr = append(m.arr,1)
m.arr = append(m.arr,2)
m.arr = append(m.arr,3)
}
In go everything is passed by value so in your code you are passing a copy of the struct to the function Dosomething(), and because the capacity of the slice is 0, the append function creates a new underlying array and returns a reference to it, and when yo do:
m.arr = append(...)
the new slice (using the new array) is lost because it is stored in m that is a copy of the original struct, if m were a *my the new slice would replace the previous in the arr property.
In Go everything is passed by value, including the this/self/me/m argument provided to receivers (aka methods).
In Go if something does not appear to be passed by value, then either a pointer to it, or a struct containing a pointer (as is the case for string, slice, etc) is being passed.
That means right now your DoSomething gets a copy of the self-object and appends to that.
So in this case Topo is correct, you just need to change DoSomething() to pass its self/this/m argument as a pointer.
func (m *my) Dosomething(){
m.arr = append(m.arr,1)
m.arr = append(m.arr,2)
m.arr = append(m.arr,3)
}
I assume this is toy code, but a couple of notes:
You could write this more efficiently as:
func (m *my) Dosomething(){
m.arr = append(m.arr,[]int{1,2,3}...)
}
And it would be more idiomatic to rename New_my() to newMy()
Related
I have an array of value pairs I want to modify. I need to add and remove values from this array as well, so I used a list. When I tried to use a list, I encountered an error.
Error CS1612 - Cannot modify the return value of 'List<(int, float)>.this[int]' because it is not a variable
So I decided I would investigate. I tried using an array instead, and it... worked fine? The following code only throws an error on arr1[0].Item1 += 1;.
static void Main()
{
List<(int, float)> arr1 = new List<(int, float)>() { (0, 0) };
(int, float)[] arr2 = new (int, float)[1];
arr1[0].Item1 += 1; // This line
arr2[0].Item1 += 1;
}
Why are tuple arrays mutable, but lists are not? Is this because arrays are simple blocks of data you can modify easily, but lists have a lot of backend behind them that complicates things? Is there a simple way to get around this, or am I going to have to make my own custom class?
Why are tuple arrays mutable, but lists are not?
The list itself is mutable, but not in the way you're doing it. Note that this isn't anything specific to tuples - it's just the case for any mutable struct.
The list indexer getter returns a value (i.e. a copy of the tuple in your case) - so modifying that value wouldn't modify the copy in the list. The compiler is trying to avoid you making a change to a value that's about to be thrown away. Array access doesn't do that - arr2[0] refers to the variable within the array. (An array is effectively a collection of variables.)
If you want to mutate the list, you can have to fetch the tuple, mutate it, then put it back:
var tuple = arr1[0];
tuple.Item1++;
arr1[0] = tuple;
Note that this also explains why you can't use list access expressions as arguments for ref parameters, but you can do the equivalent for arrays:
public void Method(ref int x) => x++;
public void CallMethod()
{
var list = new List<int> { 0 };
var array = new int[] { 0 };
Method(ref list[0]); // Error
Method(ref array[0]); // Valid
}
I have these two functions where i am trying to modify the elements. One of them compiles and other says 'val cannot be reassigned'. What is the difference between the following functions? Why does one compile and the other does not?
The one that compiles
fun <T> Array<T>.mapInPlace2(transform: (T) -> T) {
for (i in this.indices) {
this[i] = transform(this[i])
}
}
The one that says
Val cannot be reassigned
fun <T> Array<T>.mapInPlace1(transform: (T) -> T) {
for (i in this) {
i = transform(i);
}
}
Similiarly to how function parameters are final in Kotlin, so are the variables used in for loops. Essentially, writing down...
for (i in array) {
...
}
... is the equivalent of doing this in Java:
for (final int i : array) {
...
}
This helps catch some common errors, in this case - if the compiler allowed you - you'd be reassigning this local variable that just contains a reference to the real element, without changing the array. In Java terms, you'd be doing this:
for (int i : array) {
i = transform(i);
}
This new value of i is unused, it doesn't change the array itself, and it will be immediately overwritten by the value of the next element when the loop comes around.
Try this:
for(i:Int in 0 until this.size) {
this[i] = "your value"
}
You're confusing the mutability of references to objects and objects themselves.
In the first example, the structure is mutable, but the reference to it is immutable. You can change the structure of the object itself, but you can't change what structure the references points to.
In the second example, you're trying to change an immutable reference to an object, not the object itself.
If you write
val i = obj
obj can still be mutated if it's a mutable object. i can't be reassigned though, sine the reference can't be changed.
import Foundation
func insertionSort<T where T: Comparable>(var items:[T])-> [T] {
for (index, _) in items.enumerate().dropFirst() {
var j = index
while ((j > 0) && (items[j] < items[j-1])) {
swap(&items[j], &items[j-1])
j = j-1
}
}
return items
}
// Test the function
insertionSort([]) // Generic type array is not taking empty array
When I am trying to call insertionSort with empty array, I get
Cannot invoke 'insertionSort' with an argument list of type '([_])'
I am not able to figure out how to fix this.
To call generic functions in Swift, Swift needs to be able to infer the generic parameters.
One way giving the type information to Swift, is using an intermediate variable.
(Like noted in Lu_'s comment.)
let arr: [Int] = []
let result = insertionSort(arr)
Another way is using as.
let result = insertionSort([] as [Int])
(Remember, var parameter does not modify the actual argument. It just makes a mutable copy, but does not write it back to the original argument. Swift 3 removed var parameters, as it's so confusing. You may need to assign the return value of the function to a variable.)
I want to pass an array to an object and store a reference to this array. I want to be able to modify this array within this object and make sure that it's modified everywhere else.
Here is what I am trying to accomplish (how the code doesn't work)
class Foo {
var foo : Array<Int>
init(foo: Array<Int>) {
self.foo = foo
}
func modify() {
foo.append(5)
}
}
var a = [1,2,3,4]
let bar = Foo(a)
bar.modify()
print(a) // My goal is that it will print 1,2,3,4,5
My findings so far
A) The array (by default) are passed strange way. It's a reference until you modify an array length. As soon as you modify a length it will be copied and modified. As result, if I append or delete anything from it in the object it won't be seen outside
B) I can use inout on a function parameter. This will allow me to modify it within this function. However, as soon as I will try to assign it to some object member I am again struck by A)
C) I can wrap an array in some Container class. This probably is the cleanest way. However, I serialize/deserialize these objects and I would rather not put it in Container (because I will have to work around some things for serialization and deserialization and sending it to the server).
Are there anything else? Am I missing some Swift construct which allows me to do that?
You'll have to use an NSArray or NSMutableArray for this because Swift Arrays are value types so any assignment will make a copy.
You could make use of Swifts (very un-swifty) UnsafeMutablePointer.
Since (from your post) the behaviour references to arrays can't really seem be trusted, instead keep an UnsafeMutablePointer companion to the class inner array foo as well as any "external" arrays that you want to be binded to foo, in the sense that they are both just pointers to same address in memory.
class Foo {
var foo : [Int]
var pInner: UnsafeMutablePointer<Int>
init(foo: [Int]) {
pInner = UnsafeMutablePointer(foo)
self.foo = Array(UnsafeBufferPointer(start: pInner, count: foo.count))
}
func modify(inout pOuter: UnsafeMutablePointer<Int>) {
foo.append(5) // <-- foo gets new memory adress
pInner = UnsafeMutablePointer(foo)
pOuter = pInner
}
}
var a = [1,2,3,4] // first alloc in memory
var pOuter: UnsafeMutablePointer<Int> = UnsafeMutablePointer(a)
var bar = Foo(foo: a) // 'bar.foo' now at same address as 'a'
print(bar.foo) // [1,2,3,4]
bar.modify(&pOuter) // -> [1,2,3,4,5]
a = Array(UnsafeBufferPointer(start: pOuter, count: bar.foo.count))
/* Same pointer adress, OK! */
print(bar.pInner)
print(pOuter)
/* Naturally same value (same address in memory) */
print(bar.foo)
print(a)
Pointers can be dangerous though (hence the fitting type name), and, again, very un-swifty. Anyway...
/* When you're done: clear pointers. Usually when using
pointers like these you should take care to .destroy
and .dealloc, but here your pointers are just companions
to an Array property (which has a pointer an reference
counter itself), and the latter will take care of the
objects in memory when it goes out of scope. */
bar.pInner = nil
pOuter = nil
Now, what happens when either a or foo goes out of scope, will it break the variable that are not out of scope, or does Swift contain some clever reference counting that realises a memory address is still in use? I haven't investigated this, but feel free to indulge yourself in that.
From the Swift Programming Language,
Structures are always copied when they are passed around in your code, and do not use reference counting.
If you examine the contents of the array variable, you will see that indeed the append works:
class Foo {
var foo : Array
init(_ foo: Array) {
self.foo = foo
}
func modify() {
foo.append(5)
}
func printFoo() {
print("self.foo: \(foo)")
}
}
let a = [1,2,3,4]
let bar = Foo(a)
bar.modify()
bar.printFoo()
print("a: \(a)")
produces
self.foo: [1, 2, 3, 4, 5]
a: [1, 2, 3, 4]
You have taken a copy of a, not a reference to a.
a is declared a constant hence cannot be modified. If you are planning to modify the contents of a, declare it as a variable. i.e.,
var a = [1,2,3,4]
I haven't tested this but, as you are using a class to wrap the array, I see no reason why the following would not work.
class Foo {
var foo : Array<Int>
init(foo: inout Array<Int>) {
self.foo = foo
}
func modify() {
foo.append(5)
}
}
let a = [1,2,3,4]
let bar = Foo(&a)
bar.modify()
print("a: \(a)") // a: [1,2,3,4,5]
I have a simple struct called Card...
struct Card {
var order: Int? = -1
var data : [String: String]
var original : String?
And a collection object called Deck that looks like...
struct Deck {
var cards : [Card]
Deck has the reading and writing methods, which basically boils down to splitting up strings read in from a text file, and then pushing it bit by bit into the previous empty data. Here's an example...
mutating func parseGRCard(var c: Card) {
c.data["I1"] = c.original![2...4].trim()
c.data["I2"] = c.original![5...9].trim()
}
To read the file, I get each line, make a Card, and then call the parse methods on it...
let nc = Card(order: i, original: c)
parseGRCard(nc)
cards.append(nc)
When I step through this func, I see that mc's original has the expected data, the original line from the text file. I then watch parseGRCard read it and add the items to data, which now has two items. But when when it returns and nc is appended, data is empty.
I thought mutating was supposed to handle these things, but apparently I'm missing something fundamental here.
I changed your code a bit to make it compile and make it more illustrative.
append is mutating because it mutates cards.
It's parameter c is an inout parameter so that the passed Card is passed back after the function. Since Structs are value types and not reference types a new copy is actually passed to the function. This behaviour has nothing to do with the function being a mutating function.
struct Card {
var placeInDeck: Int = 0
}
struct Deck {
var cards : [Card] = []
mutating func append(inout c: Card) {
c.placeInDeck = cards.count
cards.append(c)
}
}
var cardZero = Card()
var cardOne = Card()
var deck = Deck()
deck.append(&cardZero)
deck.append(&cardOne)
cardZero.placeInDeck // 0
cardOne.placeInDeck // 1
In this case the function is not mutating because no properties from Deck are altered. The c parameter is a variable which just makes it mutable inside the scope from the function. Beware, this will be removed from Swift. When the function ends, this mutable copy of Card will not update it's original instance outside the scope of the function. The updated Card will not persist.
struct Card {
var placeInDeck: Int = 0
}
struct Deck {
var cards : [Card] = []
func updateCount(var c: Card) {
c.placeInDeck = 1
}
}
var cardZero = Card()
var cardOne = Card()
var deck = Deck()
deck.updateCount(cardZero)
deck.updateCount(cardOne)
cardZero.placeInDeck // 0
cardOne.placeInDeck // 0
From Apple's documentation methods, we can read the following regarding the mutable keyword:
However, if you need to modify the properties of your structure or
enumeration within a particular method, you can opt in to mutating
behavior for that method. The method can then mutate (that is, change)
its properties from within the method, and any changes that it makes
are written back to the original structure when the method ends.
I agree that it is could be possible to interpret the bold-marked part as as "the properties of the method, i.e., it's parameters?". From your example above, it would seem as if you have done this interpretation.
But the mutable keyword only tells us that the associated function is allowed to change (mutate) variable member values of the struct (in this case) that owns the method.
struct SingleIntegerValueStruct1 {
var myInt = 1
func LetsTryToMutateTheInteger () {
myInt += 1 // compile time error; myInt immutable
}
}
Whereas if we use the mutating keyword
struct SingleIntegerValueStruct {
var myInt = 0
mutating func LetsTryToMutateTheInteger () {
myInt += 1 // ok, mutating function
}
}
var a = SingleIntegerValueStruct(myInt: 1)
print("\(a.myInt)") // 1
a.LetsTryToMutateTheInteger()
print("\(a.myInt)") // 2
However, a struct type is and will always be a value type. So when when a struct type is passed to any function, the function will not be able to mutate the caller parameter, as it is only given a copy of it.
let nc = Card(order: i, original: c)
parseGRCard(nc) // passes _copy_ of struct typ nc to parseGRCard
cards.append(nc) // nc in this scope is stil unchanged
For wanting to use a "stand-alone" function that could mutate its input parameter, where the input is a struct, you could, as discussed in the comments, us the inout keyword on the function parameter.
We extend our example from above to include such a case:
struct SingleIntegerValueStruct {
var myInt = 0
mutating func LetsTryToMutateTheInteger () {
myInt += 1 // ok, mutating function
}
}
// "b" here is a _copy_ of "a" (in parameter), and the function
// thereafter returns a _copy_ of "b" (with state of "b" as its
// final state in the function)
func standAloneInOutFunction(inout b: SingleIntegerValueStruct) {
b.LetsTryToMutateTheInteger()
}
var a = SingleIntegerValueStruct(myInt: 1)
print("\(a.myInt)") // 1
a.LetsTryToMutateTheInteger()
print("\(a.myInt)") // 2
standAloneInOutFunction(&a)
// value copy a->b, modify(b), value copy back b->a
print("\(a.myInt)") // 3
Note however that the inout keyword does not mean that we pass by reference (as for class instances), but we simply send a value copy in and takes another value copy back, that we finally assigns to the original value type calling parameter (a).
From the Apple documentation on this keyword:
... An in-out parameter has a value that is passed in to the function,
is modified by the function, and is passed back out of the function to
replace the original value.