[英]How to leverage power of TextWriterFormat for printfn style in combination with ConditionalAttribute which requires unit result
我設置自己創建一個跟蹤函數,其行為類似於sprintf
或printfn
,但通過使用ConditionalAttribute
為發布版本禁用(JIT 在調用站點上將其刪除)。
到目前為止的結果:我認為這是不可能的。
問題圍繞這樣一個事實:當您使用Conditional("DEBUG")
屬性時,該函數必須返回單位結果。 “正常”參數按其應有的方式工作,並且方法已正確裝飾(編輯:裝飾,是的,但不會刪除可咖喱成員,請參閱討論,必須改用元組形式):
type Trace() =
[<Conditional("DEBUG")>]
static member inline trace msg b = (msg, b) |> ignore
// using it, x is unit
let x = Trace.trace "test" "foo"
(請注意,如果沒有ignore
,由於 Conditional 屬性,這將無法編譯)
但是,一旦我嘗試Printf.TextWriterFormat<'T>
任何變體,它就會失敗並且我看不到解決方法:
type Trace() =
[<Conditional("DEBUG")>]
static member inline trace msg = printfn msg // inline or not doesn't matter
// using it, x is unit
let x = Trace.trace "hello: %s" "foobar"
這在沒有屬性的情況下工作,但有了屬性,它會引發:
此表達式應具有類型
unit
但這里有類型string -> unit
該錯誤特別強調了Trace.trace "hello: %s"
。 所以看起來編譯器沒有識別出整個表達式結果是一個unit
,並引發錯誤,因為它在內部創建了一個返回string -> unit
的包裝函數,這是ConditionalAttribute
的規則所不允許的。
當我嘗試通過在函數返回類型上顯式指定:unit
或printfn msg |> ignore
作為主體來修復它時,我將失去使用具有類型安全性的文本printfn msg |> ignore
格式字符串的能力,事實上,它不會不再識別呼叫站點上的第二個參數。
因此,雖然整個函數簽名都遵守 CLR 的規則,但 F# 創建的內聯函數似乎沒有,至少在這種特定情況下沒有。
我嘗試了變體,包括kprintf
、 sprintf
,看看是否有幫助,但都無濟於事。
有任何想法嗎? 或者這是您嘗試鋪設地毯的情況之一,一旦您在一個角落適當地平滑它,它就會在另一個角落冒泡,反之亦然,即它永遠不會適合?
PS:如果您想知道我為什么想要它:只是嘗試創建一個行為類似於現有 Trace 的便利函數,但在幕后還有其他一些功能。 我目前擁有的作品,但它只需要一個字符串,而不是一個靜態類型檢查參數,所以它迫使用戶編寫如下內容:
(sprintf "Hello %s" >> Trace.trace) "foobar"
基於重載的版本。
你可能想要更多的重載
#if DEBUG
type Log() =
static member inline log(x) = printfn x
static member inline log(x,y) = printfn x y
#else
type Log =
static member inline log(x) = ()
static member inline log(x,y) = ()
#end
所以這有效:
open System.Diagnostics
type Log() =
[<Conditional("DEBUG")>]
static member log(x) = printfn x
[<Conditional("DEBUG")>]
static member log(x,y) = printfn x y
您需要切換到元組形式以允許重載並使用元組形式,因為柯里化的東西不能重載
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.