看得见的@ 看不见的magic

分享人:张实唯

入坑特性

Fire.jl

有的时候你写了一个函数,它需要很多参数

"Align two sequences locally"
function align(a::String, b::String; mismatch::Int=7, gap_open::Int=11,
               gap_extend::Int=2, threshold::Int=20)::Void
    ...
end

如果希望在命令行调用,你需要写很长一段代码 (ArgParse.jl)

using ArgParse

s = ArgParseSettings("Align two sequences locally")

@add_arg_table s begin
    "a"
        required = true
    "b"
        required = true
    "--mismatch"
        arg_type = Int
        default = 7
    "--gap_open"
        arg_type = Int
        default = 11
    "--gap_extend"
        arg_type = Int
        default = 2
    "--threshold"
        arg_type = Int
        default = 20
end

parsed_args = parse_args(s)

align(parsed_args["a"], parsed_args["b"]; parsed_args["mismatch"],
      parsed_args["gap_open"], parsed_args["gap_extend"], parsed_args["threshold"])

Fire.jl 的全部用法只需要2秒即可完全掌握

using Fire

"Align two sequences locally"
@main function align(a::String, b::String; mismatch::Int=7, gap_open::Int=11,
                     gap_extend::Int=2, threshold::Int=20)::Void
    ...
end

然后就会自动生成 --help,自动转换参数类型,智能处理 Vector, Bool 型关键字参数

➜ ~ julia align.jl
Need 2 positional arguments, see --help for what are them

➜ ~ julia align.jl --help
Align two sequences locally

Positional Arguments:
  a: String
  b: String

Optional Arguments:
  --mismatch: Int64 (default: 7)
  --gap_open: Int64 (default: 11)
  --gap_extend: Int64 (default: 2)
  --threshold: Int64 (default: 20)

➜ ~ julia align.jl --threshold 15 \
> AAAGCGCGAAGCTACGTAGCTGACTGATCGTACGTACGTCGTAGC \
> GCGCGAAGCTACGTAGAAACTGACTGATCGTACCTACGTCGTAGC

GCGCGAAGCTACGTAG---CTGACTGATCGTACGTACGTCGTAGC
||||||||||||||||   |||||||||||||| |||||||||||
GCGCGAAGCTACGTAGAAACTGACTGATCGTACCTACGTCGTAGC

安装方法: Pkg.clone("https://github.com/ylxdzsw/Fire.jl")

JsonBuilder.jl

如果需要生成一个具有固定字段的 JSON,很容易想到两个方案:

time   = ["2017-01-17", "2017-01-18", "2017-01-19", ...]
open   = [118.339996, 119.400002, 120.449997, ...]
top    = [120.239998, 120.5, 120.089996, ...]
bottom = [118.220001, 119.709999, 119.370003, ...]
close  = [120, 119.989998, 119.779999, ...]

approch1 = """{
    "x":     [$(join(map(x->"\"$x\"", time), ","))],
    "open":  [$(join(open, ","))],
    "close": [$(join(close, ","))],
    "high":  [$(join(top, ","))],
    "low":   [$(join(bottom, ","))],
    "decreasing": {"line": {"color": "#7F7F7F"}},
    "increasing": {"line": {"color": "#17BECF"}},
    "line":  {"color": "rgba(31,119,180,1)"},
    "type":  "ohlc",
    "xaxis": "x",
    "yaxis": "y"
}"""

approch2 = JSON.json(Dict(
    "x"          => time,
    "open"       => open,
    "close"      => close,
    "high"       => top,
    "low"        => bottom,
    "decreasing" => Dict("line"  => Dict("color" => "#7F7F7F")),
    "increasing" => Dict("line"  => Dict("color" => "#17BECF")),
    "line"       => Dict("color" => "rgba(31,119,180,1)"),
    "type"       => "ohlc",
    "xaxis"      => "x",
    "yaxis"      => "y"
))

拼字符串的方法有几个问题:

  • 插值非常麻烦,尤其是嵌套的字典和列表,而且插入字符串容易忘记加引号
  • 字段名需要自己加双引号
  • 出来的JSON字符串既不是 pretty 的也不是 minified 的 (除非你花时间去修饰)
  • 而直接使用 JSON.jl 又有另外几个问题:

  • 字典字面量比较麻烦,Julia 本身的字典语法就不是特别漂亮
  • 格式与 JSON 不同,不能“粘贴即用”
  • 需要建立哈希再序列化,浪费运算 (虽然大多时候不是问题)
  • JsonBuilder.jl 使用类似 JavaScript 的高兼容性语法,采取特殊的插值规则,并且在编译期完成格式解析

    approch3 = @json """{
        x: $time,
        open: $open,
        close: $close,
        high: $top,
        low: $bottom,
        decreasing: {line: {color: "#7F7F7F"}},
        increasing: {line: {color: "#17BECF"}},
        line: {color: "rgba(31,119,180,1)"},
        type: "ohlc",
        xaxis: "x",
        yaxis: "y"
    }"""
    

    JsonBuilder 具备以下优势

  • 字段名可加引号可不加,出来的 JSON 总是会自动加上,此过程编译期完成
  • 插值使用 JSON.jl,可以直接插入列表、字典
  • 可以直接写 JSON 的字面量,方便复制粘贴
  • 无论如何缩进、换行,出来的 JSON 总是会自动去除所有空白字符,此过程编译期完成
  • 额外的注释语法、mixin 语法 (详见项目 README)
  • 安装方法: Pkg.clone("https://github.com/ylxdzsw/JsonBuilder.jl")

    RedisAlchemy.jl

    使用 Redis 来(伪)持久化应用数据,或者协调多进程并行计算,而不需要学习 Redis

    using RedisAlchemy
    
    conn = RedisConnectionPool(10)
    
    list = RedisList{String}("task")
    
    push!(list, 2)
    
    unshift!(list, 3)
    
    length(list)
    
    list[1:2]
    
    sort!(list)
    
    list[:]
    

    安装方法: Pkg.clone("https://github.com/ylxdzsw/RedisAlchemy.jl")