How would you write this:
if case .SomeEnum(3) = enumType where myInt == 3 {
//I don't need this case
} else {
//This is the case I need
}
I know I could use guard:
guard case .SomeEnum(3) = enumType where myInt == 3 else {
//This is the case I need
}
but I don't think it is clean, since it is not really a case in which the function is not able to finish. Also, guard expects me to return from the function.
Any other alternatives?
You cannot negate a pattern (as far as I know), and your first solution
using if/else looks fine to me, the intention of the code is clearly
visible.
A switch statement would be an alternative:
switch enumType {
case .SomeEnum(3) where myInt == 3:
break // I don't need this case
default:
// This is the case I need
// ...
}
With regard to your remark
Also, guard expects me to return from the function.
that is not entirely true. You are expected to leave the current scope.
So this would compile and work as expected:
repeat {
guard case .SomeEnum(3) = enumType where myInt == 3 else {
// This is the case I need
// ...
break
}
} while false
but I would not consider that a better solution.
Related
I am using text/scanner package to parse some arbitrary expressions. I am currently trying to implement a not in option, that is, if the current identifier is not, and the next is in, parse it using function notin(left, right), and otherwise we parse it as negate(right).
I've essentially got the code to manage these cases however, I am unable to rewind the scanner in case the next token is not in. I've tried by recording the position and then reassigning it later, but to no avail and haven't been able to find a different solution.
func readToken(stream *scanner.Scanner) {
switch stream.Scan() {
case scanner.Ident:
switch stream.TokenText() {
case "in":
in(left, right)
case "not":
oldPosition := stream.Position
nextToken := stream.Scan()
if nextToken == scanner.Ident {
switch stream.TokenText() {
case "in":
fmt.Println("notin")
default:
// how do we rewind the scanner?
stream.Position = oldPosition
fmt.Println("negate default")
}
} else {
fmt.Println("negate no-ident")
}
}
}
}
How can I rewind the scanner when I don't find a valid identifier?
Edit, I also tried using Peek() as below, but that still changes the state to the point that I'd need to rewind as well.
// other code
case "not":
nextIdent, err := getNextIdent(stream)
if err != nil {
fmt.Println("negate no-ident")
} else {
switch nextIdent {
case "in":
fmt.Println("notin")
default:
fmt.Println("negate default")
}
}
// other code
func getNextIdent(s *scanner.Scanner) (string, error) {
var nextIdent string
ch := s.Peek()
// skip white space
for s.Whitespace&(1<<uint(ch)) != 0 {
ch = s.Next()
}
if isIdentRune(ch, 0) {
nextIdent = string(ch)
ch = s.Next()
nextIdent += string(ch)
for i := 1; isIdentRune(ch, i); i++ {
ch = s.Next()
if s.Whitespace&(1<<uint(ch)) != 0 {
break
}
nextIdent += string(ch)
}
return nextIdent, nil
}
return "",errors.New("not a ident")
}
Note, the code I've got is a forked from Knetic/govaluate combined with a PR from GH user generikvault and some other forks. The full code can be found on my Github profile
By looking at the API references of text/scanner, I can't seem to find a way to rewind the scanner the way you want.
However, the Peek() method would get you the next rune without advancing the scanner. Inside the "not" case, you can use it to peek in advance to see if it matches.
I want to use an if-statement inside the switch but I keep getting an expected expression error. I would be grateful if anyone could help me to solve this issue.
switch ([ApplicationModel getApplicationType]) {
case CSApplication: {}
break;
case RAApplication:
{
if (indexPath.row == FloorLevelIndex || indexPath.row == RoomIndex)
{
[cell setUserInteractionEnabled: YES];
}
}
break;
default:
break;
}
If FloorLevelIndex and RoomIndex are types, you won't be able to compare a number to a type (hence the error). You probably want the number representation of those or define them with a NSInteger value
Make sure that [ApplicationModel getApplicationType] returns the valid data type that swtich case supports.
The variable used in a switch statement can only be integers,
convertable integers (byte, short, char), strings and enums
Should be like this:
switch ([ApplicationModel getApplicationType]) {
case CSApplication:
break;
case RAApplication:
if (indexPath.row == FloorLevelIndex || indexPath.row == RoomIndex)
{
[cell setUserInteractionEnabled: YES];
}
break;
default:
break;
}
I just tried this code in my Xcode and it works fine:
NSLayoutAttribute attr = NSLayoutAttributeLeft;
switch (attr) {
case NSLayoutAttributeTop: {}
break;
case NSLayoutAttributeLeft: {
if (YES) {
NSLog(#"works");
}
}
break;
default:
break;
}
So the structure of your switch statement is correct.
In my app I am using a custom error type ProgrammerError with three error values .Messiness, .Procrastination and .Arrogance (these are just examples). Later in the code I need to cast the errors to NSError. The NSError objects have code properties starting from 0 following the order or error values I declared: 0, 1, 2 etc.
enum ProgrammerError: ErrorType {
case Messiness
case Procrastination
case Arrogance
}
(ProgrammerError.Messiness as NSError).code // 0
(ProgrammerError.Procrastination as NSError).code // 1
(ProgrammerError.Arrogance as NSError).code // 2
My question is: Is there a way to set different error codes for the enumeration values? For example, can I set Messiness to have code value of 100 instead of 0?
You can implement var _code: Int { get } property.
enum ProgrammerError: ErrorType {
case Messiness
case Procrastination
case Arrogance
var _code: Int {
switch self {
case .Messiness:
return 100
case .Procrastination:
return 101
case .Arrogance:
return 102
}
}
}
(ProgrammerError.Messiness as NSError).code // 100
(ProgrammerError.Procrastination as NSError).code // 101
(ProgrammerError.Arrogance as NSError).code // 102
You can also implement var _domain: String { get } if you need.
But I must warn you, these methods are undocumented so they might stop working in future.
Or, you may try explicit conversion.
extension FileActionError {
func getCode() -> Int {
switch self {
case .BadFileNodeIndex: return 1
case .BadFileNodePath: return 2
}
}
func toNSError() -> NSError {
return NSError(domain: "", code: getCode(), userInfo: [NSLocalizedDescriptionKey: "\(self)"])
}
}
Might not what you expected.
I am using FreeStreamer in Swift and am trying to set the onStateChange block.
audioStream.onStateChange = { (state) in
if state == kFsAudioStreamBuffering {
//blah
}
}
I am getting this error:
Binary operator '==' cannot be applied to operands of type '(FSAudioStreamState)' and 'FSAudioStreamState'
Edit: Still the same error without the parentheses around state in the block params
EDIT: As a temporary fix, state.value == kFsAudioStreamBuffering.value works
try putting a dot (.) before kFsAudioStreamBuffering
something like this:
if state == .kFsAudioStreamBuffering {
//blah
}
UPDATE: Try this instead
audioStream.onStateChange = { state in
if state.value == kFsAudioStreamBuffering.value {
//blah
}
}
It should be something like this to make it work.
self.audioControler?.onStateChange = { (state:FSAudioStreamState) -> Void in
switch state {
case .fsAudioStreamRetrievingURL:
This question already has answers here:
Compile Error with: switch, "expected expression before"
(3 answers)
Closed 8 years ago.
I have a switch case like this:
switch ([weatherCode intValue]) {
case 1:
...
break;
case 2:
....
break;
}
But i want to alloc an object in that case, like NSString *string = #"hello";
but it keep gives me an error expect expression which i don't understand what's going on at all. Please help.
Thanks.
I had same problem before, simply add a {} in your case, all your problem will be solved.
Such as:
switch ([weatherCode intValue]) {
case 1:
{
...
}
break;
case 2:
{
...
}
break;
}
You need braces if you want initialise variable:
switch ([weatherCode intValue]) {
case 1:{
NSString *string = #"hello";
}
break;
case 2: {
....
}
break;
}
In (Objective-)C(++) the statements while(...) { ... }, for(...) { ... }, switch(...) { ...} etc. contain a single block statement (if (...) { ... } else { ... } contains two). The scope of declarations within a block is just that block, and it is an error to declare the same variable twice within a block.
The block of a switch contains a number of case ...: labels - labels do not delimit blocks, they are just points within a block that control flow can jump to. This makes switch statements in C different than in some other languages where each branch is independent (as the two blocks in an if/else are independent in C). A C switch is just a "computed goto" into a single block. This is why the break; statement exists, without it control flow just continues from one "branch" to the next.
Another consequence of this is that different branches cannot declare the same variable names, unlike for if/else statements.
Finally only statements and not declarations can be labelled, and as a case ...: is a form of label there cannot be a declaration immediately following one - so you cannot start a "branch" with a declaration.
If the variables you wish to declare within a branch are for use only in that branch (as they would be if declared in either of the blocks of an if/else) then you can solve all the problems by enclosing the branch in braces, { ... }, to make it into a block statement - blocks can be labelled and can contain local declarations. E.g. something along the lines of:
switch (expr)
{
case 1:
{
NSString *var;
// use var
break;
}
case 2:
{
NSNumber *var;
// use var
break;
}
...
}
// no var here
If you are assigning to variables which you need to use after the switch then you must declare them before the switch, as the body of a switch is a block and hence a local declaration scope. E.g. something along the lines of:
NSString *var = nil;
switch (expr)
{
case 1:
...
var = ...;
break;
case 2:
...
var = ...;
break;
...
}
// use var here
HTH
Try doing it like this:
switch ([weatherCode intValue]) {
case 1: {
...
}
break;
case 2: {
....
}
break;
...
}
Use some braces :
switch ([weatherCode intValue]) {
case 1:{
NSString *string = #"hello";
}
break;
case 2:{
NSString *string = #"hello";
}
break;
}
In the switch, cases acts like block so you may need to set the { }. You don't need to explicitly alloc the NSString if using ARC.
switch ([weatherCode intValue]) {
case 1:
{
//your code for case 1
}
break;
case 2:
{
//your code for case 2
}
break;
}