使用 Clojure Spec 测试 java.time.LocalDate 的有效实例
Test for a Valid Instance of java.time.LocalDate using Clojure Spec
我正在尝试使用 Clojure 规范来定义包含 java.time.LocalDate 元素的数据结构:
(s/def :ex/first-name string?)
(s/def :ex/last-name string?)
(s/def :ex/birth-date (s/valid? inst? (java.time.LocalDate/now)))
(s/def :ex/person
(s/keys :req [:ex/first-name
:ex/last-name
:ex/birth-date]))
(def p1 #:ex{:first-name "Jenny"
:last-name "Barnes"
:birth-date (java.time.LocalDate/parse "1910-03-15")})
(println p1)
产生以下输出
#:ex{:first-name Jenny, :last-name Barnes, :birth-date #object[java.time.LocalDate 0x4ed4f9db 1910-03-15]}
然而,当我测试 p1 是否符合 :ex/person 规范时,它失败了:
(s/valid? :ex/person p1)
ClassCastException java.lang.Boolean cannot be cast to clojure.lang.IFn clojure.spec.alpha/spec-impl/reify--1987 (alpha.clj:875)
仔细观察 Clojure examples for inst?,我发现:
(inst? (java.time.Instant/now))
;;=> true
(inst? (java.time.LocalDateTime/now))
;;=> false
但是,我看不出 returns 错误的明显原因。这似乎是我问题的根源,但我还没有找到解决方案,希望得到一些帮助。
您可能正在寻找 instance?
- 而您的示例失败了,因为在:
(s/def :ex/birth-date (s/valid? inst? (java.time.LocalDate/now)))
这部分(s/valid? inst? (java.time.LocalDate/now))
应该是一个函数(谓词),而不是布尔值。完整代码:
(s/def :ex/first-name string?)
(s/def :ex/last-name string?)
(s/def :ex/birth-date #(instance? java.time.LocalDate %))
(s/def :ex/person
(s/keys :req [:ex/first-name
:ex/last-name
:ex/birth-date]))
(def p1 #:ex{:first-name "Jenny"
:last-name "Barnes"
:birth-date (java.time.LocalDate/parse "1910-03-15")})
(s/valid? :ex/person p1)
=> true
inst?
在这里不起作用,因为 Inst
是一个协议,用于扩展 java.util.Date
和 java.time.Instant
:
(defprotocol Inst
(inst-ms* [inst]))
(extend-protocol Inst
java.util.Date
(inst-ms* [inst] (.getTime ^java.util.Date inst)))
(defn inst?
"Return true if x satisfies Inst"
{:added "1.9"}
[x]
(satisfies? Inst x))
(extend-protocol clojure.core/Inst
java.time.Instant
(inst-ms* [inst] (.toEpochMilli ^java.time.Instant inst)))
并且您可以使用 satisfies?
来检查某个对象是否满足给定的协议:
(satisfies? Inst (java.time.LocalDate/parse "1910-03-15"))
=> false
我正在尝试使用 Clojure 规范来定义包含 java.time.LocalDate 元素的数据结构:
(s/def :ex/first-name string?)
(s/def :ex/last-name string?)
(s/def :ex/birth-date (s/valid? inst? (java.time.LocalDate/now)))
(s/def :ex/person
(s/keys :req [:ex/first-name
:ex/last-name
:ex/birth-date]))
(def p1 #:ex{:first-name "Jenny"
:last-name "Barnes"
:birth-date (java.time.LocalDate/parse "1910-03-15")})
(println p1)
产生以下输出
#:ex{:first-name Jenny, :last-name Barnes, :birth-date #object[java.time.LocalDate 0x4ed4f9db 1910-03-15]}
然而,当我测试 p1 是否符合 :ex/person 规范时,它失败了:
(s/valid? :ex/person p1)
ClassCastException java.lang.Boolean cannot be cast to clojure.lang.IFn clojure.spec.alpha/spec-impl/reify--1987 (alpha.clj:875)
仔细观察 Clojure examples for inst?,我发现:
(inst? (java.time.Instant/now))
;;=> true
(inst? (java.time.LocalDateTime/now))
;;=> false
但是,我看不出 returns 错误的明显原因。这似乎是我问题的根源,但我还没有找到解决方案,希望得到一些帮助。
您可能正在寻找 instance?
- 而您的示例失败了,因为在:
(s/def :ex/birth-date (s/valid? inst? (java.time.LocalDate/now)))
这部分(s/valid? inst? (java.time.LocalDate/now))
应该是一个函数(谓词),而不是布尔值。完整代码:
(s/def :ex/first-name string?)
(s/def :ex/last-name string?)
(s/def :ex/birth-date #(instance? java.time.LocalDate %))
(s/def :ex/person
(s/keys :req [:ex/first-name
:ex/last-name
:ex/birth-date]))
(def p1 #:ex{:first-name "Jenny"
:last-name "Barnes"
:birth-date (java.time.LocalDate/parse "1910-03-15")})
(s/valid? :ex/person p1)
=> true
inst?
在这里不起作用,因为 Inst
是一个协议,用于扩展 java.util.Date
和 java.time.Instant
:
(defprotocol Inst
(inst-ms* [inst]))
(extend-protocol Inst
java.util.Date
(inst-ms* [inst] (.getTime ^java.util.Date inst)))
(defn inst?
"Return true if x satisfies Inst"
{:added "1.9"}
[x]
(satisfies? Inst x))
(extend-protocol clojure.core/Inst
java.time.Instant
(inst-ms* [inst] (.toEpochMilli ^java.time.Instant inst)))
并且您可以使用 satisfies?
来检查某个对象是否满足给定的协议:
(satisfies? Inst (java.time.LocalDate/parse "1910-03-15"))
=> false