In Swift the ampersand sign & is for inout parameters. Like
var value = 3
func inoutfunc(inout onlyPara: Int) {
onlyPara++
}
inoutfunc(&value) // value is now 4
That doesn't look like onlyPara is a pointer, maybe it is and get dereferences immediately when using it inside the function.
Is onlyPara a pointer?
When I don't need a IntPointer type, why are the framework methods using a NSErrorPointer type? Because they can't change the methods because of existing Objective-C code?
But why is then Swift converting &error to NSErrorPointer, is that autoboxed?
var errorPtr: NSErrorPointer = &error
And when I have a NSErrorPointer. How do I dereference it?
var error: NSError = *errorPtr // won't work
Maybe someone can enlighten me. Using only Swift is easy. I think the questions are one chunk of knowledge over & between swift and Objective-C (as the address of operator)
Solution to 4. I found out how to dereference it:
var error: NSError = errorPtr.memory!
I suggest you read the Pointers section of the Using Swift with Cocoa and Objective-C guide: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html#//apple_ref/doc/uid/TP40014216-CH8-XID_16
There is a table at the bottom of the Pointers section, which explains how class pointers bridge to Swift pointer types. Based on that, the NSError pointer should be AutoreleasingUnsafePointer<NSError>. Searching trough the headers for NSErrorPointer yields this:
typealias NSErrorPointer = AutoreleasingUnsafePointer<NSError?>
Why the extra ? after NSError? I guess it's because NSError can also be nil.
Hope it helps!
Swift 3
var errorPtr: NSErrorPointer = nil
callSomeFunctionThatReceivesParamByReference(.., error: errorPtr)
if let error = errorPtr?.pointee { ... }
Related
I'm a Golang newbie but I thought I had got the essentials of pointers and references straight, but apparently not:
I have a method that must return a []github.Repository, which is a type from the Github client in go.
The API call returns the results paginated so I must cycle until there's no more results, and add the result of each call to the allRepos variable, and return that. Here's what I have so far:
func (s *inmemService) GetWatchedRepos(ctx context.Context, username string) ([]github.Repository, error) {
s.mtx.RLock()
defer s.mtx.RUnlock()
opt := &github.ListOptions{PerPage: 20}
var allRepos []github.Repository
for {
// repos is of type *[]github.Repository
repos, resp, err := s.ghClient.Activity.ListWatched(ctx, "", opt)
if err != nil {
return []github.Repository{}, err
}
// ERROR: Cannot use repos (type []*github.Repository) as type github.Repository
// but dereferencing it doesn't work, either
allRepos = append(allRepos, repos...)
if resp.NextPage == 0 {
break
}
opt.Page = resp.NextPage
}
return allRepos, nil
}
My question: how can I append the results of each call and return a result of type []github.Repository?
Also, why doesn't dereferencing work here? I've tried replacing allRepos = append(allRepos, repos...) with allRepos = append(allRepos, *(repos)...) but I get this error message:
Invalid indirect of (repos) (type []*github.Repository)
Well, something is not okay here:
You say in the comment that "repos is of type *[]github.Repository" but the compiler's error message indicates that repos is of type []*Repository". The compiler is never (except when buggy) wrong.
Note that *[]github.Repository and []*Repository are completely different types, especially the second is not a slice of Repositories and you cannot (really, there is no way) dereference these pointers during append(): You have to write a loop and dereference each slice item and append one by one.
What is strange too: github.Repository and Repository seem to be two different types one from package github, the other from the current package. Again, you'll have to get that straight too.
Note that there are no references in Go. Stop thinking about these immediately: This is a concept from other languages which is not helpful (as inexistent) in Go.
In your example the dereferencing is not correct. You should make it like this:
allRepos = append(allRepos, *repos...)
Here a simple example with dereferencing a pointer to a slice of string. https://play.golang.org/p/UDzaG5z8Pf
Here is the code used inside the Beego MVC architecture.
var maps []orm.Params
//Pallets Completed already.
o.Raw("Select SUM(Things) as AllTheThings FROM SomeTable").Values(&maps)
numThings := strconv.Atoi(maps[0]["AllTheThings"].(string))
c.Data["Stuff"] = maps[0]["AllTheThings"]
Error:
multiple-value strconv.Atoi() in single-value context
Trying to figure out how I can get data out with our ORM and type cast it so arithmetic can be done on it.
Any more details please let me know.
strconv.Atoi has a signature of:
func Atoi(s string) (int, error)
you should check the error before using the result, like so:
var maps []orm.Params
//Pallets Completed already.
o.Raw("Select SUM(Things) as AllTheThings FROM SomeTable").Values(&maps)
numThings, err := strconv.Atoi(maps[0]["AllTheThings"].(string))
if err != nil {
// couldn't convert
}
c.Data["Stuff"] = maps[0]["AllTheThings"]
Somewhere in the API I use I have a function which takes &[&A] as argument but I only have a vector of A objects. When I try to use this function with
following syntax
pub struct A(pub u64);
fn test(a: &[&A]){}
fn main() {
let v = vec![A(1), A(2), A(3)];
let a = &v[..];
test(a);
}
I have a error:
<anon>:12:9: 12:10 error: mismatched types:
expected `&[&A]`,
found `&[A]`
(expected &-ptr,
found struct `A`) [E0308]
I have made some attempts but without any success:
let a = &v[&..]
and
let a = &v[&A]
How can I make &[&A] from Vec<A>?
Short answer: you can't. These types are not compatible with each other.
What you could do if this is really what the API needs is
test(&v.iter().collect::<Vec<_>>());
But this allocates a new vector. If you are the author of the API, consider changing it: &[&T] is a weird type to work with since you need different owners for the slice and the objects in it. &[T] already has a pass-by-reference semantic of the inner objects.
I am trying to write a csv parser using the example provided here. It works great for all native types but I am having trouble with any structs that contain a timestamp of type time.Time. It exits with an error of "cannot convert this type".
This is the code.
//For each field in a given struct...
//Get a field
val := sv.Field(i)
// this is necessary because Kind can't tell
// distinguish between a primitive type
// and a type derived from it. We're looking
// for a Value interface defined on
// the pointer to this value
_, ok := val.Addr().Interface().(Value)
if ok {
val = val.Addr()
kind = value_k
} else {
switch Kind {
case reflect.Int, reflect.Int16, reflect.Int8,
reflect.Int32, reflect.Int64:
kind = int_k
case reflect.Uint, reflect.Uint16, reflect.Uint8,
reflect.Uint32, reflect.Uint64:
kind = uint_k
case reflect.Float32, reflect.Float64:
kind = float_k
case reflect.String:
kind = string_k
default:
// Kind is Struct here
kind = value_k
_, ok := val.Interface().(Value)
if !ok {
err = os.NewError("cannot convert this type ")
this = nil
return
}
}
}
What this code does is take an interface and a reader. It attempts to match the field headers in the reader (csv file) with field names in the interface. It also reflects on the interface (struct) and collects positional a type information for later setting the fields in the iterator. It is this step that is failing for non-native types.
I've tried a few methods to work around this but the only thing that seems to work is changing the timestamp to a string. I am undoubtedly missing something and would greatly appreciate some guidance.
As an exercise, I'm trying to create a wrapper for sqlite3. I've got the bridging header set up, and I can see the tool tips for the sqlite3 functions, but I can't figure out how to call sqlite3_open
sqlite3.h contains the following definitions of sqlite3 and sqlite3_open:
typedef struct sqlite3 sqlite3;
SQLITE_API int sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
Which means that sqlite3_open takes as a trailing parameter a pointer to a pointer to an anonymous structure, which seems clear enough in the tooltip:
func sqlite3_open(filename: CString, ppDb: CMutablePointer<COpaquePointer>) -> CInt
Knowing that CMutablePointer means to pass in &T, the closest I've come is:
class Database {
var handle:COpaquePointer
init(file:String) {
let error = sqlite3_open(file as CString, &handle)
}
deinit {
sqlite3_close(handle)
}
}
There's no error on the sqlite3_close line, so I think I'm at least close, but the sqlite3_open line yields:
Cannot convert the expression's type 'CInt' to type '$T9'
Any clues on how to do this?
Please, no answers that say to use FMDB or other Objective-C based interfaces. As I said, this is at least partially an exercise in figuring out how to use C libraries from swift.
The problem is not with the handle parameter, but with the string conversion. The following works…
class Database {
var handle: COpaquePointer = nil
init(file: NSString) {
let error = sqlite3_open(file.cStringUsingEncoding(NSUTF8StringEncoding), &handle)
}
}
I'm unsure as to why the 'as CString' doesn't work.
When you add #import <sqlite3.h> into Bridging-Header, the sqlite3 C/C++ API will be 'translated' into native swift function. So, the sqlite3_open will be like below.
func sqlite3_open(file:String, inout ppdb:COpaquePointer) -> Int
And you can call this function with "String" type parameter instead of "CString". The swift compiler will translate "String" into UTF8 String data stream automatically.
let error = sqlite3_open(filePath, &db)