F#使用关键字和递归函数

时间:2014-11-17 15:34:48

标签: asynchronous recursion f# idisposable tail-recursion

据我所知,use关键字一旦超出范围就会处理绑定的IDisposable,所以考虑这个递归函数:

let rec AsyncAcceptMessages(client : WebSocket) =
  async {
    let! message = client.AsyncReadMessage
    use reader = new StreamReader(message)
    let s = reader.ReadToEnd()
    printf "%s" <| s
    do! AsyncAcceptMessages client
  }

让我们假装编译器没有找到使用尾递归的方法,在每次递归后会StreamReader处理吗?

更新

Tomas的回应让我想到了一种方法来解决它,当你真正期待某些东西回来的时候,但如果你什么都没想到呢?就像在这个例子中StreamWriter

一样
let rec AsyncAcceptMessages(client : WebSocket) =
  async {
    let! message = client.AsyncReadMessage
    if(not(isNull message)) then 
      let s = 
        use reader = new StreamReader(message)
        reader.ReadToEnd()
      use writer = new StreamWriter(client.CreateMessageWriter(WebSocketMessageType.Text), Encoding.UTF8)
      writer.Write s
      printf "%s" <| s
    do! AsyncAcceptMessages client
  }

1 个答案:

答案 0 :(得分:5)

正如您所说,StreamReader只会在执行从递归调用返回后(即从不)处理

还有另一个问题,即do!不被视为尾递归调用,因此如果要创建无限尾递归循环,则需要使用return!(否则)你的代码会泄漏内存。)

在这种情况下,您可以轻松地使用它进行修复,因为您没有使用StreamReader进行任何异步操作,因此您只需创建一个普通的本地范围:

let rec AsyncAcceptMessages(client : WebSocket) =
  async {
    let! message = client.AsyncReadMessage
    let s = 
      use reader = new StreamReader(message)
      reader.ReadToEnd()
    printf "%s" <| s
    return! AsyncAcceptMessages client
  }

如果你想打电话,例如AsyncReadToEnd,然后您可以执行以下操作:

let rec AsyncAcceptMessages(client : WebSocket) =
  async {
    let! message = client.AsyncReadMessage
    let! s =
      async { use reader = new StreamReader(message)
              return! reader.ReadToEnd() }
    printf "%s" <| s
    return! AsyncAcceptMessages client
  }