I have the following functions:
func (c *Class)A()[4]byte
func B(x []byte)
I want to call
B(c.A()[:])
but I get this error:
cannot take the address of c.(*Class).A()
How do I properly get a slice of an array returned by a function in Go?
The value of c.A(), the return value from a method, is not addressable.
Address operators
For an operand x of type T, the address operation &x generates a
pointer of type *T to x. The operand must be addressable, that is,
either a variable, pointer indirection, or slice indexing operation;
or a field selector of an addressable struct operand; or an array
indexing operation of an addressable array. As an exception to the
addressability requirement, x may also be a composite literal.
Slices
If the sliced operand is a string or slice, the result of the slice
operation is a string or slice of the same type. If the sliced operand
is an array, it must be addressable and the result of the slice
operation is a slice with the same element type as the array.
Make the value of c.A(), an array, addressable for the slice operation [:]. For example, assign the value to a variable; a variable is addressable.
For example,
package main
import "fmt"
type Class struct{}
func (c *Class) A() [4]byte { return [4]byte{0, 1, 2, 3} }
func B(x []byte) { fmt.Println("x", x) }
func main() {
var c Class
// B(c.A()[:]) // cannot take the address of c.A()
xa := c.A()
B(xa[:])
}
Output:
x [0 1 2 3]
Have you tried sticking the array in a local variable first?
ary := c.A()
B(ary[:])
Related
recently I was trying to see the address of my variable and I have this question.
var age: Int = 5
withUnsafePointer(to: age) {
print($0) // 0x00007ffee3362750
print($0.pointee) // 5
}
withUnsafePointer(to: &age) {
print($0) // 0x000000010d226330
print($0.pointee) // 5
}
why it shows different memory address and why it shows the same value for the pointee?
var strarr = [1, 2]
withUnsafePointer(to: strarr[0]) {
print("\($0)") // 0x00007ffee3362750
print("\($0.pointee)") // 1
}
withUnsafePointer(to: strarr[1]) {
print("\($0)") // 0x00007ffee3362750
print("\($0.pointee)") // 2
}
withUnsafePointer(to: &strarr[0]) {
print("\($0)") // 0x0000600002755760
print("\($0.pointee)") // 1
}
withUnsafePointer(to: &strarr[1]) {
print("\($0)") // 0x0000600002755768
print("\($0.pointee)") // 2
}
for the array, why it shows the same memory address for index 1 and 2, when I'm not passing the address of the variable and why it shows a different memory address for index 1 and 2 when I'm passing the memory address?
Appreciate your answer and looking forward to understand this
The differences you see come from the fact that you are using two different overloads of withUnsafePointer, I'll list them in the same order you used them:
func withUnsafePointer<T, Result>(to value: T, _ body: (UnsafePointer<T>) throws -> Result) rethrows -> Result
, and
func withUnsafePointer<T, Result>(to value: inout T, _ body: (UnsafePointer<T>) throws -> Result) rethrows -> Result
The difference between the two is the inout qualifier used for the value parameter.
Now, let's try to understand what happens behind the scenes.
First, 0x00007ffee3362750 looks like a stack pointer, while 0x000000010d226330 looks like a heap pointer. Stack addresses start at the top of the allocated memory for the program, and decrease with every function call (and increase when the function returns).
This indicates that the first overload of withUnsafePointer create a temporary writable variable from the one passed as the argument. This is needed as UnsafePointer needs an inout reference to work with, and a regular parameter is readonly.
This means that the implementation of the non-inout overload of withUnsafePointer looks something like this:
func withUnsafePointer<T, Result>(to value: T, _ body: (UnsafePointer<T>) throws -> Result) rethrows -> Result {
var value = value // shadow the argument, create a readwrite location
return try withUnsafePointer(&value, body)
}
Thus, the first call needs to allocate an intermediate memory location, and this is why you see two different addresses, it's because the addresses are not pointing to the same memory location. However, since both memory locations start with the same value, printing the pointee results in identical output.
Now, let's talk about the array example. The behaviour you see has the same cause: stack allocations. What happens is:
program starts executing, stack pointer has value P (random name)
non-inout withUnsafePointer is called, this is a function call, and stack is reserved for the function; stack pointer is P - N
withUnsafePointer creates the temporary writable variable, and executes
withUnsafePointer returns, and frees the stack memory, at this stack pointer gets back to P
second non-inout withUnsafePointer is called, the stack pointer is back to P - N, however since there were no other function calls between the two, the same stack address is reserved for the temporary writable variable, thus the UnsafePointer instance has the same address
Here, even if the UnsafePointer points to the same address, the values at that address are different, corresponding to values of arr[0] and arr[1].
As for the inout calls, the UnsafePointer point to the actual addresses of the items in the array buffer.
This is how you can get different values for the non-inout calls too:
withUnsafePointer(to: strarr[0]) {
print("\($0)")
print("\($0.pointee)")
}
// this adds a nested function call, which also decreases the stack pointer
// resulting in the temporary location not being on the same stack address
func test() {
withUnsafePointer(to: strarr[1]) {
print("\($0)")
print("\($0.pointee)")
}
}
test()
I am trying to sort a 2D array of custom struct, id is optional, but when I try to unwrap them I get another error: Cannot assign value of type '()' to subscript of type '[SomeObject]'
for x in 0..<tableData.count {
tableData[x] = tableData[x].sort(by: {$0.id! > $1.id!})
}
What can I do here?
sort is a mutating method and sorts the collection in-place, i.e. the return type of this method is Void.
So, there is no need to store the result of sort back to tableData, i.e.
for x in 0..<tableData.count {
tableData[x].sort(by: {$0.id! > $1.id!})
}
Make sure that tableData is a var.
In the following example, the xcode compiler has a warning on the first line:
Variable 'y' was never mutated, consider changing to let constant.
while var (x,y) = stack.tryPop() {
// .. x is mutated
x++
// y is not mutated
}
// in Stack struct:
func tryPop -> (x:Int,y:Int)? {}
However if I change the var to let, as follows:
while let (x,y) = stack.tryPop() {
... then I get a compiler error: Cannot pass immutable value to mutating operator: 'x' is a 'let' constant.
Of course, I can safely use var instead of let, and ignore the compiler warning, but I would like to know if there is a way of getting around the warning by specifying that x is mutating and y is constant, when assigning from a tuple?
You can do this with Swift pattern matching:
while case (var x, let y)? = stack.tryPop() {
// .. x is mutated
x++
// y is not mutated
}
You can read more about Swift Patterns here.
I'm trying to build a function with swift that will map an array, divide each value in the array by 3, then spit out a new array. This is what I have so far:
func divideby3Map<T, U>(y: [T], z: T -> U) -> [U] {
let array = [int]()
let divideby3Array = array.map { [y] / 3 }
return dividedby3Array
}
divideby3Map([1,2,3,4,5])
Where T and U are the original array, and the new array being returned respectively, and it's done using generics.
I'm sure this isn't written properly, I'm stuck in terms of the right syntax. For example, since the array being returned is represented by the generic [U], I assume I have to use it somewhere in the array being returned, not sure where though.
When writing a generic function, it’s sometimes easier to approach it in 3 steps: first write the code stand-alone using a specific type. Then write the code as a function, still with a specific type. Finally, change the function to be generic.
The first part, dividing an array by 3, can be done like this:
let a = [1,2,3,4,5]
// map is run on the array of integers, and returns a new
// array with the operation performed on each element in a:
let b = a.map { $0 / 3 }
// so b will be [0,0,1,1,1]
// (don’t forget, integer division truncates)
Note the closure you provide between the { } is an operation that will be applied to each element of the array. $0 represents the element, and you divide it by 3. You could also write it as a.map { i in i / 3 }.
To put this into its own function:
func divideby3Map(source: [Int]) -> [Int] {
return source.map { $0 / 3 }
}
No need to declare a fresh array – map will create one for you. You can then return that directly (you can assign it to a temporary if you prefer, but that isn’t really necessary).
Finally, if you want to make it generic, start by adding a placeholder:
func divideby3Map<T>(source: [T]) -> [T] {
return source.map { $0 / 3 }
}
Note, there’s only a need for one placeholder, T, because you are returning the exact same type you are passed in.
Except… this won’t compile, because the compiler doesn’t know that T is guaranteed to provide two critical things: the ability to divide (a / operator), and the ability to create new T from integer literals (i.e. to create a T with value 3 to divide by). Otherwise, what if we passed an array of strings or an array of arrays in?
To do this, we need to “constrain” T so our function will only accept as arguments types that provide these features. One such protocol we can use to constrain T is IntegerType, which does guarantee these features (as well as some other ones like +, * etc):
func divideby3Map<T: IntegerType>(source: [T]) -> [T] {
return source.map { $0 / 3 }
}
divideby3Map(a) // returns [0,0,1,1,1]
let smallInts: [UInt8] = [3,6,9]
divideby3Map(smallInts) // returns [1,2,3]
Why is it that I cannot mutate an implicitly unwrapped optional variable?
Here is a short example the reproduces the issue:
With Array
var list: [Int]! = [1]
list.append(10) // Error here
Immutable value of type '[Int]' only has mutating members named 'append'
With Int
var number: Int! = 1
number = 2
number = 2 + number
number += 2 // Error here
Could not find an overload for '+=' that accepts the supplied arguments
Because the way you are trying to mutate them is by mutating the values (which are immutable) instead of mutating the var.
In Swift value types are immutable. All and always.
Mutation is not a mutation of the value, it's a mutation of the variable that contains the value.
In the case of the Int, the += operator gets a structure on the left and an Int on the right, and it cannot add a structure to an int.
In the case of the Array the append is a mutating member. But it's being invoked on an immutable value that is not directly stored in a variable. It can only operate on values that are directly stored in a variable (which is what makes them mutable: the fact that they are stored in a variable. They are not really mutable, the variable is).
Update:
This has been fixed in Xcode Beta 5 with one small caveat:
var list: [Int]! = [1]
list.append(10)
var number: Int! = 1
number! += 2
number += 2 // compile error
The array works as expected, but it seems that right now the integer still requires an explicit unwrap to allow using +=
Currently, this is just the nature of Optionals (whether implicitly unwrapped or not). The unwrap operator returns an immutable value. This is likely to be fixed or a better solution will be provided in the future.
The only way around it for now is to wrap the array in a class:
class IntArray {
var elements : [Int]
}