elixir如何保持累加器

时间:2016-02-21 11:17:51

标签: elixir

我想了解灵药流。
首先,我有一个列表,迭代一个范围和多个2。

- (BOOL)startReading {  
        NSError *error;  
        AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];  
        AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];  
            if (!input) {  
                NSLog(@"%@", [error localizedDescription]);  
                return NO;  
            }  
            _qrLB.text=@"Loading....";  
            _captureSession = [[AVCaptureSession alloc] init];  
            [_captureSession addInput:input];  
            AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];  
            [_captureSession addOutput:captureMetadataOutput];  
            dispatch_queue_t dispatchQueue;  
            dispatchQueue = dispatch_queue_create("myQueue", NULL);  
            [captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatchQueue];  
            [captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]];  
            _videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];  
            [_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];  
            [_videoPreviewLayer setFrame:_viewPreview.layer.bounds];  
            [_viewPreview.layer addSublayer:_videoPreviewLayer];  
            [_captureSession startRunning];  
        return YES;  
    }  
    #pragma mark  
    #pragma mark Stop reading QR Code  
    -(void)stopReading{  
        [_captureSession stopRunning];  
        _captureSession = nil;  
        [_videoPreviewLayer removeFromSuperlayer];  
    }  
    #pragma mark  
    #pragma mark Capture QR Code  
    -(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{  
        NSLog(@"qrcode1");  
        if (metadataObjects != nil && [metadataObjects count] > 0) {  
            AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0];  
            if ([[metadataObj type] isEqualToString:AVMetadataObjectTypeQRCode]) {  
                [_lblStatus performSelectorOnMainThread:@selector(setText:) withObject:[metadataObj stringValue] waitUntilDone:NO];  
                [self performSelectorOnMainThread:@selector(stopReading) withObject:nil waitUntilDone:NO];  
                _isReading = NO;  
            }  
        }  
        NSLog(@"Value of qrcodetext = %@", _lblStatus.text);  
        ReceiveVC *view = [self.storyboard instantiateViewControllerWithIdentifier:@"ReceiveVC"];  
        view.imageURL=_lblStatus.text;  
        view.title = @"";  
        [self.navigationController pushViewController:view animated:YES];  
        NSLog(@"qrcode2");  
    }  

这里一切都很清楚,每个枚举都会返回一个列表,以便进一步处理列表。它对列表中的每个元素迭代四次 让我们用流构建它:

iex(5)>   stream = 1..3 |>
...(5)>   Enum.map(&IO.inspect(&1)) |>
...(5)>   Enum.map(&(&1 * 2)) |>
...(5)>   Enum.map(&IO.inspect(&1)) |>
...(5)>   Enum.reduce(4, &+/2)
1
2
3
2
4
6
16

此处,它只针对范围内的每个数字进行一次迭代,而不像上面的示例那样使用 enum 。我不明白的是,当它只迭代一次时,Enum.reduce的累加器如何保持值并由它们自己进行递归调用?
当我按照以下方式迭代枚举时:

iex(4)>   stream = 1..3 |>
...(4)>   Stream.map(&IO.inspect(&1)) |>
...(4)>   Stream.map(&(&1 * 2)) |>
...(4)>   Stream.map(&IO.inspect(&1)) |>
...(4)>   Enum.reduce(4, &+/2)
1
2
2
4
3
6
16

然后我可以成像, enum.reduce 如何将累加器传递给下一个递归调用。

但是如果按流执行迭代只执行一次,流如何通过累加器进行下一次递归调用?

1 个答案:

答案 0 :(得分:3)

不确定你遗失/询问是什么,但让我试一试。首先,您必须知道流如何工作并在Elixir中表示:流只是一组在可枚举上运行的函数。当你组成流(例如,printf)时,你没有对流做任何“具体”的事情,你只是将函数添加到将用于处理初始可枚举的函数列表中。当用流调用1..3 |> Stream.map(...) |> Stream.map(...)时,就是当你开始迭代可枚举时(一次一个元素)。

通过检查Enum.reduce/3的进度,可以更好地理解你的例子:

Enum.reduce/3

正如你所看到的,发生了一些神奇的事情:当我们调用iex> printer1 = fn el -> IO.puts "1st iteration, el: #{inspect el}"; el end iex> printer2 = fn el -> IO.puts "2nd iteration, el: #{inspect el}"; el end iex> reducer = fn el, acc -> ...> IO.puts "reducing, el: #{inspect el}, acc: #{inspect acc}\n" ...> el + acc ...> end iex> 1..3 |> Stream.map(printer1) |> Stream.map(&(&1 + 10)) |> Stream.map(printer2) |> Enum.reduce(0, reducer) 1st iteration, el: 1 2nd iteration, el: 11 reducing, el: 11, acc: 0 1st iteration, el: 2 2nd iteration, el: 12 reducing, el: 12, acc: 11 1st iteration, el: 3 2nd iteration, el: 13 reducing, el: 13, acc: 23 36 时,流开始展开,我们遍历每个元素映射三个函数并在其上调用Enum.reduce/3和累加器

它可以帮助您研究Enumerable协议的文档,因为该协议用于从流中获取元素(通常一次一个)。当您链接reducer操作时(就像在第一个示例中那样),Enum.map/2将收到一个列表作为其第一个参数,因此将使用列表的Enum.reduce/3协议:它的实现只是迭代列表并将列表中的元素“生成”到Enumerable,一次一个。当您链接Enumerable.reduce操作时,Stream.map/2将收到一个流,因此将使用流的Enum.reduce/3协议:它的实现将每个元素从原始可枚举中取出({{1} }),应用流操作(在这种情况下为Enumerable链),并一次生成一个结果。

希望我为你做的事情更清楚,如果你还有疑问,请问任何问题:)。