代码之家  ›  专栏  ›  技术社区  ›  Abraham P

从一个javascript绑定到错误路径的无标记联合

  •  1
  • Abraham P  · 技术社区  · 8 年前

    我正在尝试为amqplib npm包编写reasonml绑定:

    http://www.squaremobius.net/amqp.node/

    尤其是该功能:

    http://www.squaremobius.net/amqp.node/channel_api.html#channel_get

    class type amqpMessageT = [@bs] {
      pub content: nodeBuffer
    };
    
    type amqpMessage = Js.t(amqpMessageT);
    
    type gottenMessage = Js.Nullable.t(amqpMessage);
    
    type qualifiedMessage = Message(gottenMessage) | Boolean(bool);
    
    class type amqpChannelT = [@bs] {
      pub assertQueue: string => queueParams => Js.Promise.t(unit);
      pub consume: string => (amqpMessage => unit) => unit;
      pub ack: amqpMessage => unit;
      pub get: string => Js.Promise.t(qualifiedMessage);
      pub purgeQueue: string => Js.Promise.t(unit);
      pub deleteQueue: string => Js.Promise.t(unit);
      pub sendToQueue: string => nodeBuffer => messageParams => unit;
    };
    

    然后我有以下代码:

     ....
     channel##get("MyQueue")
     |> Js.Promise.then_(message => {
       switch message {
         | Boolean(false) => Js.Promise.resolve(Js.log("No Message"));
         | Message(msg) => Js.Promise.resolve(Js.log("Has Message, Will Travel"));
         | Boolean(true) => Js.Promise.resolve(Js.log("Impossible Message"!));
       }
      }
    

    但是,这会沿着“message(msg)”路径 总是 ,即使JS调用返回false。

    现在添加以下绑定:

    let unsafeGet: amqpChannel => string => Js.Promise.t(gottenMessage) = [%bs.raw{|function(channel, queueName) {
      return channel.get(queueName).then((value) => {
        if(value === false) {
          return Promise.resolve(null)
        } else {
          return Promise.resolve(value)
        }
      })
    }|}];
    

    我可以回避这个问题,但我不太喜欢使用 bs.raw 如果我诚实的话。我最初的无标签工会类型有什么问题?我如何解决这个问题?

    1 回复  |  直到 8 年前
        1
  •  3
  •   glennsl Namudon'tdie    8 年前

    在ocaml语言中没有未标记的联合类型,也没有运行时类型信息,因此必须实现自己的类型、检查和转换,才能将其转换为可用的形式。

    例如,可以使用抽象类型来表示“未知”类型,并使用一个伴随函数来检查其类型,将其强制转换为该类型,然后将其转换为 qualifiedMessage :

    type unknownMessage;
    
    let classifyMessage = (value: unknownMessage) =>
      switch (Js.Types.classify(value)) {
      | JSString(s) => Message(Js.Nullable.return(s))
      | JSNull      => Message(Js.null)
      | JSFalse     => Boolean(false)
      | JSTrue      => Boolean(true)
      | _           => failwith("invalid runtime type")
      }
    

    另外,作为旁注,如果通过公开抽象类型和函数/外部而不是公开“原始”对象来抽象底层数据结构,那么在定义接口的方式上,您将获得很大的灵活性,并且可以隐藏这个额外的转换步骤。

    推荐文章