您不需要很多bash代码即可在bash中实现类或对象。
说100行。
Bash具有关联数组,可用于实现具有继承,方法和属性的简单对象系统。
因此,您可能会定义这样的类:
class Queue N=10 add=q_add remove=q_remove
创建此Queue的实例可以这样完成:
class Q:Queue N=100
要么
inst Q:Queue N=100
由于类是通过数组实现的,因此class和inst实际上是同义词-类似于javascript。
可以将项目添加到此队列中,如下所示:
$Q add 1 2 aaa bbb "a string"
可以将项目删除到变量X中,如下所示:
$Q remove X
对象的转储结构可以这样完成:
$Q dump
这将返回如下内容:
Q {
      parent=Queue {
                     parent=ROOT {
                                   this=ROOT
                                   0=dispatch ROOT
                                 }
                     class=Queue
                     N=10
                     add=q_add
                     remove=q_remove
                     0=dispatch Queue
                   }
      class=Q
      N=4
      add=q_add
      remove=q_remove
      0=dispatch Q
      1=
      2=ccc ddd
      3=
      4=
    }
使用这样的类函数创建类:
class(){
    local _name="$1:"                            # append a : to handle case of class with no parent
    printf "$FUNCNAME: %s\n" $_name
    local _this _parent _p _key _val _members
    _this=${_name%%:*}                           # get class name
    _parent=${_name#*:}                          # get parent class name
    _parent=${_parent/:/}                        # remove handy :
    declare -g -A $_this                         # make class storage
    [[ -n $_parent ]] && {                       # copy parent class members into this class
        eval _members=\"\${!$_parent[*]}\"       # get indices of members
        for _key in $_members; do                # inherit members from parent
            eval _val=\"\${$_parent[$_key]}\"    # get parent value
            eval $_this[$_key]=\"$_val\"         # set this member
        done
    }
    shift 1
    # overwrite with specific values for this object
    ROOT_set $_this "$@" "0=dispatch $_this" "parent=${_parent:-ROOT}" "class=$_this"
}
注意:定义新的类或实例时,您可以覆盖任何成员值或函数。
Bash关联数组有一个使这个工作整洁的怪癖:$ Q [0]}与$ Q相同。这意味着我们可以使用数组名称来调用方法分派函数:
dispatch(){
    local _this=$1 _method=$2 _fn
    shift 2
    _fn="$_this[$_method]"                       # reference to method name
    ${!_fn} $_this "$@"
}
不利的一面是我无法使用[0]来存储数据,因此我的队列(在这种情况下)从index = 1开始。或者,我可以使用关联索引,例如“ q + 0”。
要获取并设置成员,您可以执行以下操作:
# basic set and get for key-value members
ROOT_set(){                                       # $QOBJ set key=value
    local _this=$1 _exp _key _val
    shift
    for _exp in "$@"; do
        _key=${_exp%%=*}
        _val="${_exp#*=}"
        eval $_this[$_key]=\"$_val\"
    done
}
ROOT_get(){                                       # $QOBJ get var=key
    local _this=$1 _exp _var _key
    shift
    for _exp in "$@"; do
        _var=${_exp%%=*}
        _key=${_exp#*=}
        eval $_var=\"\${$_this[$_key]}\"
    done
}
并转储对象结构,我这样做:
注意:bash中的OOP不需要此操作,但是很高兴看到如何制作对象。
# dump any object
obj_dump(){                                      # obj_dump <object/class name>
    local _this=$1 _j _val _key; local -i _tab=${2:-(${#_this}+2)}  # add 2 for " {"
    _tab+=2                                      # hanging indent from {
    printf "%s {\n" $_this
    eval "_key=\"\${!$_this[*]}\""
    for _j in $_key; do                          # print all members
        eval "_val=\"\${$_this[\$_j]}\""
        case $_j in
            # special treatment for parent
            parent) printf "%*s%s=" $_tab "" $_j; ${!_val} dump $(( _tab+${#_j}+${#_val}+2 ));;
                 *) printf "%*s%s=%s\n" $_tab "" $_j "$_val";;
        esac
    done
    (( _tab-=2 ))
    printf "%*s}\n" $_tab ""
    return 0
}
我的OOP设计未考虑对象内的对象-继承的类除外。您可以单独创建它们,也可以制作特殊的构造函数,例如class()。* obj_dump *将需要修改以检测内部类以递归方式打印它们。
哦! 并且我手动定义了ROOT类以简化类功能:
declare -gA ROOT=(    \
  [this]=ROOT         \
  [0]="dispatch ROOT" \
  [dump]=obj_dump     \
  [set]="ROOT_set"    \
  [get]="ROOT_get"    \
)
通过一些队列函数,我定义了一些这样的类:
class Queue          \
    in=0 out=0 N=10  \
    dump=obj_dump    \
    add=q_add        \
    empty=q_empty    \
    full=q_full      \
    peek=q_peek      \
    remove=q_remove
class RoughQueue:Queue     \
    N=100                  \
    shove=q_shove          \
    head_drop=q_head_drop
创建了一些Queue实例并使它们工作:
class Q:Queue N=1000
$Q add aaa bbb "ccc ddd"
$Q peek X
$Q remove X
printf "X=%s\n" "$X"
$Q remove X
printf "X=%s\n" "$X"
$Q remove X
printf "X=%s\n" "$X"
class R:RoughQueue N=3
$R shove aa bb cc dd ee ff gg hh ii jj
$R dump