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

vto*_*ola 3 recursion f# asynchronous tail-recursion idisposable

据我所知,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
  }
Run Code Online (Sandbox Code Playgroud)

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

UPDATE

当你真正期待某些东西回来时,托马斯的反应向我展示了一种修复它的方法,但是如果你什么都没想到呢?就像在这个例子中的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
  }
Run Code Online (Sandbox Code Playgroud)

Tom*_*cek 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
  }
Run Code Online (Sandbox Code Playgroud)

如果你想打电话给eg 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
  }
Run Code Online (Sandbox Code Playgroud)