在 Ruby 中,return
在块甚至嵌套块内调用将转移控制并从最内层的包装方法返回,我说的是 proc。在 Ruby 中,lambdareturn
从块本身返回,调用方法继续,这也是 Objective-C 块的工作方式。
有没有办法让 Ruby 的 proc 语义在 Objective-C 中返回?我想要一个块内的返回来返回外部方法。
在 Ruby 中,return
在块甚至嵌套块内调用将转移控制并从最内层的包装方法返回,我说的是 proc。在 Ruby 中,lambdareturn
从块本身返回,调用方法继续,这也是 Objective-C 块的工作方式。
有没有办法让 Ruby 的 proc 语义在 Objective-C 中返回?我想要一个块内的返回来返回外部方法。
简短的回答是否定的,块内的 return 语句只会从块中返回。如下所示,您当然可以使用异常、@try
语句和宏的组合来构建一些不优雅的东西,但最后我认为这比其他任何事情都更令人困惑。
@interface MPReturnFromNestedBlockException : NSException
+ (void) returnExceptionWithResult:(id)result;
@end;
@implementation MPReturnFromNestedBlockException
+ (void) returnExceptionWithResult:(id)result
{
MPReturnFromNestedBlockException *exception = (id)
[self exceptionWithName:@"MPReturnFromMethodException"
reason:nil
userInfo:@{@"result":result}];
[exception raise];
}
@end
#define abruptReturn(value)\
({ [MPReturnFromNestedBlockException returnExceptionWithResult:value]; })
#define blockMayReturnAbruptly(block)\
({\
id result = nil;\
@try { block(); }\
@catch(MPReturnFromNestedBlockException *exception) {\
result = exception.userInfo[@"result"];\
}\
result;\
})
int main (int argc, const char * argv[])
{
@autoreleasepool {
NSArray *numbers = @[@1, @2, @3];
id value = blockMayReturnAbruptly(^{
[numbers enumerateObjectsUsingBlock:^(id numA, NSUInteger index, BOOL *stop) {
double a = [numA doubleValue];
[numbers enumerateObjectsUsingBlock:^(id numB, NSUInteger index, BOOL *stop) {
double b = [numB doubleValue];
NSLog(@"%f x %f = %f", a, b, a*b);
if (a * b > 3)
abruptReturn(@(a*b));
}];
}];
});
NSLog(@"Result = %@", value);
}
return 0;
}
输出如下:
1.000000 x 1.000000 = 1.000000
1.000000 x 2.000000 = 2.000000
1.000000 x 3.000000 = 3.000000
2.000000 x 1.000000 = 2.000000
2.000000 x 2.000000 = 4.000000
Result = 4
我不熟悉 Ruby,但 ObjC 块对其封闭方法施加控制的唯一方法是让该方法测试其返回值。
这可能很简单:
- (id)bloviate:(id (^)(void))bombast
{
// The method returns the results of the Block call;
// thus, strictly speaking, the method returns when
// the Block does.
return bombast();
}
或者您可以检查返回值并有条件地从该方法返回:
- (id)elucidate:(BOOL (^)(id))explanation
{
id obj = /* Get some object */;
if( explanation(obj) ) {
return obj;
}
// Else continue
}