I am trying to use inline if condition as follows:
topDisplay.text!.rangeOfString(".") != nil ? call function A : call function B
The idea here is if there is "." in the topDisplay.text! then call function A, otherwise, call function B. The method, rangeOfString, returns nil if no "." is found. So I am wondering is it possible to check nil within inline condition expression and making function call at the same time.
Your code is correct, assuming you put the calls to actual functions in there, i.e.:
func functionA() -> String { return "A" }
func functionB() -> String { return "B" }
topDisplay.text?.rangeOfString(".") != nil ? functionA() : functionB()
If you’re getting an error message, the most likely reason is functionA and functionB return different types:
func functionA() -> String { return "A" }
func functionB() -> Int { return 1 }
// error: could not find an overload for '!=' that accepts the supplied arguments
topDisplay.text?.rangeOfString(".") != nil ? functionA() : functionB()
In classic Swift error message style, this gives you an error about the valid != comparison not about the problem with A and B returning incompatible types.
However, given you aren’t showing in your code the assignment of the result, I suspect you are actually wanting to run these functions for their side-effects not for the value they return. If this is the case do not do this. The ?: operator is there for evaluating two possibilities as an expression. If you want side effects, use an if:
if topDisplay.text?.rangeOfString(".") != nil {
sideEffectfulFunctionA()
}
else {
sideEffectfulFunctionB()
}
Related
I'm a beginner with Go, and I'm now writing a function which can call an API. The function receives a part of the url (/user, /account, etc) and the struct to convert the returned json to (the structs User or Account for example) as arguments.
So I now have this:
func (self *RestClient) request(action string, return_type interface{}) interface{} {
res, _ := goreq.Request{Uri:self.url + action}.Do()
var item return_type
res.Body.FromJsonTo(&item)
return item
}
And I try to call this function using (with Index being the struct for the return type):
self.request("/api/v1/public/index", Index)
But this doesn't work. I get the following errors:
return_type is not a type
type Index is not an expression
I guess I understand why this is. I think I have to somehow find out the type of return_type and then convert return_type to that type, before using it as the type for item. I have no idea how though.
About the second error I have no idea. I don't even understand what is meant by it.
Could anybody help me out? How can I make this work? Or should this be done in a completely different way all together? All tips are welcome!
A few hints based on this code:
Don't use self - use a meaningful identifier
Don't use interface{} to avoid dealing with the type system
Don't use reflection
Don't ignore errors returned (as from FromJsonTo or goreq.Request)
Don't use a library like goreq unless you are sure you need it (you don't) - you are pulling in lots of code you don't need and it is teaching you bad habits like attempting to use empty interface and reflection to solve simple problems.
Have a look at the definition of FromJsonTo - if you look through this library you'll see it isn't saving you much effort and is adding lots of complexity. Here is how you could do it without the library:
func (c *RestClient) Request(action string, resource interface{}) error {
res, err := http.Get(c.url + action)
if err != nil {
return err
}
defer res.Body.Close()
return json.NewDecoder(res.Body).Decode(resource)
}
Or use an interface and move the decoding to the resource (which could embed a default decoder):
type Decoder interface {
Decode(r io.Reader) error
}
// RequestDecode fetches a request and feeds it to the decoder
func (c *RestClient) RequestDecode(action string, resource Decoder) error {
res, err := http.Get(c.url + action)
if err != nil {
return err
}
defer res.Body.Close()
return resource.Decode(res.Body)
}
I'll first say that you should always check for errors from any function that possibly returns one.
The error you are seeing is because you are trying to declare a variable item as type return_type and that is the name of a function argument.
The other error is from Index being a type declaration and not a concrete value of the Index type.
I agree with Volker's comment but to put it in code, you could use something like this:
func (self *RestClient) request(action string, return_type interface{}) {
res, err := goreq.Request{Uri:self.url + action}.Do()
if err != nil {
// Do something with error here.
}
res.Body.FromJsonTo(return_type)
}
var index Index
rest_client.request("/some/path", &index)
This allows flexibility but could lead to strange cases if you forget to pass a pointer to the value return_type.
I've tried to create a function in Go that used to retry any fail query functions (usually because serialization issue).
func retryer(functionA func(interface{}) (interface{}, []error), maxRetry int, waitBetween time.Duration) interface{} {
//when no error in functionA, retryer returns whatever functionA returns
//when maxRetry is reached, returns nil
}
The functions I want to retry are looked like this
func GetTopStudent(classId string) ([]Student, []error) {
//queries top 10 students for class with classId
}
func GetAverageStudentScores(classId string, from time.Time, until time.Time) ([]Pair, []error) {
//queries all average score using aggregate, grouping by studentId
//Pair behaves like C++ pair<string,string>
}
But, the results is a compile error
cannot use GetTopStudent (type func(string) ([]Student, []error)) as type func(interface{}) (interface {}, []error) in argument to retryer
I've tried to modify it a little and I got another compile error
cannot use GetTopStudent (type func(string) ([]Student, []error)) as type func(string) (interface {}, []error) in argument to retryer
Can anyone help me creating a general function to wrap a function to retry on error?
A better way to solve your problem would be to use closures.
For example, change the type of retryer:
func retryer(f func() error, maxRetry int, waitBetween time.Duration) error {
// retry and wait logic
err := f()
// error handling, retry, and wait logic
return err
}
Now call functions to be retried as:
// ...
classId := "some value"
// ...
var st []Student
var errors []error
err := retryer(func() error {
st, errors = GetTopStudent(classId)
// handle errors
return nil
}, numTries, waitTime)
// use st here
I'm trying to learn Swift and I'm stuck to a very simple thing. How to write a function that returns an enum. The following code doesn't compile:
import Foundation
enum MyResponse {
case Even (String, String)
case Odd (String)
}
func checkNumber(number : Int) -> MyResponse // <---- Error message
{
if (number % 2 == 0) {
return MyResponse.Even(String(number), " is even")
}
return MyResponse.Odd("odd")
}
let v1 = checkNumber(1)
switch v1 {
case .Even(arg1, arg2):
println("\(arg1) --> \(arg2)")
case .Odd(arg):
println("\(arg)")
}
I get the error message "Use of undeclared type".
What am I doing wrong? What is the correct way to return enum value from a function.
Your MyResponse from line #3 is different from MyResponse in line #8. There is unprintable character between "My" and "Response" in line #8.
Swift programming book says,
By returning a tuple with two distinct values, each of a different
type, the function provides more useful information about its outcome
than if it could only return a single value of a single type.
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/gb/jEUH0.l
I searched on internet but couldn't find any examples of it.So I tried myself like example below, but if you've got better please let me know.. Thanks in advance.
var statusCode = 404
var statusMessage = "No Site"
let http404 = ( sCode : statusCode , sMessage : statusMessage)
func responseFromWS (foo : Int, bar : String) -> (param1 : Int, param2 : String)
{
statusCode = foo
statusMessage = bar
let httpProtocol = ( statusCode , statusMessage)
return httpProtocol
}
responseFromWS(500, "Internal Server Error")
In other languages (including objective c) you can return one value only (of any type), but in some cases you might need to return more than one value.
The pattern usually applied in those cases is to pass references to variables to the function for all additional return values - a typical case is a reference to a NSError * variable, which the function either sets to nil if no error occurs, or to an instance of NSError in case of error.
Such problem is elegantly solved in swift using multiple return values packed in a tuple.
The way you are using this features seems correct, but what's wrong is defining the statusCode and statusMessage variables outside the function scope:
func responseFromWS (foo : Int, bar : String) -> (code: Int, message: String)
{
let statusCode: Int = foo
let statusMessage: String = bar
return (code: statusCode, message: statusMessage)
// Note: you can also write as follows, because the parameter names are defined in the function signature
// return (statusCode, statusMessage)
}
You can use the return value in different ways. As a tuple:
let response = responseFromWS(500, "Internal Server Error")
// Using named parameters
println(response.code) // Prints 500
println(response.message) // Prints "Internal Server Error"
// using parameters by index
println(response.0) // Prints 500
println(response.1) // Prints "Internal Server Error"
As individual variables:
let (code, message) = responseFromWS(500, "Internal Server Error")
println(code)
println(message)
As a subset of individual variables (if you need only a subset of the returned values):
// Assign message only, discard code
let (_, message) = responseFromWS(500, "Internal Server Error")
println(message)
In addition to the uses mentioned by #Antonio, I have used them to return "pseudo-structs" where a function calculates several values, but the definition of a new struct type would really not be used anywhere else.
An example: when calculating true bearing and distance on the surface of the earth, one may choose to return some kind of polar coordinate struct, but the reverse azimuth (not a trivial relation in true geodesy) is also calculated as a by product. In implementations in other languages I have done this by defining a struct type to return the three doubles - but this struct type is never used except to call this function! Better to say
let (distance, azimuth, reverseAzimuth) = coordinate(vectorTo: otherCoordinate)
than having your future self look up the definition of and then unpack some obscure struct.
I have to write unit tests for several functions with similar signature and return values (an object and an error), which must pass similar test conditions.
I would like to avoid writing:
func TestFunc1(t *testing.T) {
// tests on return values
}
func TestFunc2(t *testing.T) {
// tests identical for Func1
}
func TestFunc3(t *testing.T) {
// tests identical for Func1
}
...
(See this go playground example for a more complete context)
(yes, go playground doesn't support yet go test, only go run, and issue 6511 is there to request that feature)
How would you use reflection (reflect package) in order to write only one test which would:
call each function in turn?
test their return value?
I have seen:
"How to properly use .Call in reflect package, Golang?", using Value.Call
"Selecting a function from a list of functions in Golang"
But I miss a complete example for calling functions and using the returned values in a test.
Once I understood that everything must use or return the type Value, here is what I came up with.
The trick is to use:
ValueOf in order to get a value of the receiver
Value.MethodByName to find a function of that receiver value
Value.IsNil to test for nil returned value.
Main extract of the test code:
var funcNames = []string{"Func1", "Func2", "Func3"}
func TestFunc(t *testing.T) {
stype := reflect.ValueOf(s)
for _, fname := range funcNames {
fmt.Println(fname)
sfunc := stype.MethodByName(fname)
// no parameter => empty slice of Value
ret := sfunc.Call([]reflect.Value{})
val := ret[0].Int()
// That would panic for a nil returned err
// err := ret[1].Interface().(error)
err := ret[1]
if val < 1 {
t.Error(fname + " should return positive value")
}
if err.IsNil() == false {
t.Error(fname + " shouldn't err")
}
}
}
See a runnable example in go playground.
Note that if you are calling that test function with a non-existent function name, that will panic.
See that example here.
runtime.panic(0x126660, 0x10533140)
/tmp/sandbox/go/src/pkg/runtime/panic.c:266 +0xe0
testing.func·005()
/tmp/sandbox/go/src/pkg/testing/testing.go:383 +0x180
----- stack segment boundary -----
runtime.panic(0x126660, 0x10533140)
/tmp/sandbox/go/src/pkg/runtime/panic.c:248 +0x160
reflect.flag.mustBe(0x0, 0x13)
/tmp/sandbox/go/src/pkg/reflect/value.go:249 +0xc0
reflect.Value.Call(0x0, 0x0, 0x0, 0xfeef9f28, 0x0, ...)
/tmp/sandbox/go/src/pkg/reflect/value.go:351 +0x40
main.TestFunc(0x10546120, 0xe)
/tmpfs/gosandbox-3642d986_9569fcc1_f443bbfb_73e4528d_c874f1af/prog.go:34 +0x240
Go playground recover from that panic, but your test program might not.
That is why I added to the test function above:
for _, fname := range funcNames {
defer func() {
if x := recover(); x != nil {
t.Error("TestFunc paniced for", fname, ": ", x)
}
}()
fmt.Println(fname)
That produces (see example) a much nicer output:
Func1
Func2
Func3
Func4
--- FAIL: TestFunc (0.00 seconds)
prog.go:48: Func2 should return positive value
prog.go:51: Func3 shouldn't err
prog.go:32: TestFunc paniced for Func4 : reflect: call of reflect.Value.Call on zero Value
FAIL