(require '[taoensso.truss :as truss])
假设我们有一张描述我圈子的地图。圆总是有一个中心,但可以通过直径或半径来描述:
{:center [1, 2] :diameter 10}
{:center [1, 2] :radius 5}
上述两个圈子都描述了相同的圈子。
所以说我们有一个期望圆形图作为输入的函数,我们怎样才能最好地用truss来断言呢?代码的开头可能如下所示:
(defn circle-tosser
[circle-map]
(truss/have map? circle-map)
(truss/have number? :in (:center circle-map))
(str "Tossing " circle-map))
(circle-tosser {:center [1, 2] :radius 5})
;; => "Tossing {:center [1 2], :radius 5}"
问题当然是我们不能直接断言这些密钥的值具有certine属性,因为它们不存在neccicerily。例如,以下声明要求两个键同时出现:
(defn circle-tosser
[circle-map]
(truss/have map? circle-map)
(truss/have number? :in (:center circle-map))
(truss/have number? (:diameter circle-map))
(truss/have number? (:radius circle-map))
(str "Tossing " circle-map))
(circle-tosser {:center [1, 2] :diameter 10}) ; Unhandled Exception
(circle-tosser {:center [1, 2] :diameter 10 :radius 5})
;; => "Tossing {:center [1 2], :diameter 10, :radius 5}"
然后你可以开始编写像
这样的东西(defn circle-tosser
[circle-map]
(truss/have map? circle-map)
(truss/have number? :in (:center circle-map))
(when (contains? circle-map :diameter)
(truss/have number? (:diameter circle-map)))
(when (contains? circle-map :radius)
(truss/have number? (:radius circle-map)))
(str "Tossing " circle-map))
(circle-tosser {:center [1, 2] :diameter 10})
;; => "Tossing {:center [1 2], :diameter 10}"
但是这开始变得过于冗长且无法阅读,这是不幸的,因为提供可访问的文档(以代码的形式),是桁架目的的一部分。
也许你可以想出一个改进的方法来解决这个问题?
答案 0 :(得分:1)
有两种方法可以解决您的问题。
(1)始终生成radius
而不是diameter
(2)如果你不能做(1),那么每个对圆的引用都需要包含在如下的转换函数中:
(defn normalize [c]
(if (contains? c :diameter)
(-> c
(assoc :radius (/ (:diameter c) 2))
(dissoc :diameter))
c))
,您的代码看起来像
(defn circle-tosser
[circle-map]
(let [c (normalize circle-map) ]
(truss/have map? c)
(truss/have number? :in (:center c))
(str "Tossing " c)))
我总是喜欢解决方案(1),但有时候(2)无法避免。
答案 1 :(得分:0)
你可以做的一件事是定义一个隐藏重复代码的函数,比如
<Grid DataContext="{Binding ElementName=lb_Configuration, Path=SelectedItem}">
<StackPanel HorizontalAlignment="Left">
<TextBlock Text="Basic_Param" Style="{StaticResource Heading2}" Margin="0,0,0,5" />
<StackPanel HorizontalAlignment="Left">
<DataGrid Name="dgBasicInfo" DataContext="{Binding ElementName=lb_Configuration, Path=SelectedItem}" AutoGenerateColumns="True" Margin="0,0,0,15" BorderThickness="2">
<DataGrid.Columns>
<DataGridTextColumn Header="ModelName" Binding="{Binding Path=ModelName}"/>
<DataGridTextColumn Header="CategoryName" Binding="{Binding Path=CategoryName}" />
<DataGridTextColumn Header="InputAddress" Binding="{Binding Path=IntputAddress}" />
<DataGridTextColumn Header="OutputAddress" Binding="{Binding Path=OutputAddress}" />
<DataGridTextColumn Header="DiagAddress" Binding="{Binding Path=DiagAddress}" />
<DataGridTextColumn Header="Description" Binding="{Binding Path=Description}" />
</DataGrid.Columns>
</DataGrid>
</StackPanel>
<TextBox Margin="5" Grid.Column="1" Text="{Binding Path=ModelName}" /></Grid>
当然,对于这个例子,我们要引入一个互斥的概念。但是,正如Alan Thompson建议的那样,将数据标准化可能会更好。