В определенных ситуациях, особенно когда у вас много переменных и вы точно знаете границы переменных (минимальное и максимальное значение переменных), вы можете использовать словарь и побитовый &
.
Пример ниже будет таким, где каждая переменная может иметь 2 возможных значения (0 или 1, это пример, основанный на том, как рассчитываются разрешения на чат Discord).
set permissions {
perm1 0x00000001
perm2 0x00000002
perm3 0x00000004
perm4 0x00000008
perm5 0x00000010
perm6 0x00000020
perm7 0x00000040
perm8 0x00000080
}
set permDict [dict create {*}$permissions]
proc getPermList {perms} {
# Ensure perms is an integer
if {![string is integer -strict $perms]} {
return -code error "Not an integer: $perms"
}
# This list will contain matched permissions
set permList [list]
dict for {permission value} $::permDict {
if {$perms & $value} {
lappend permList $permission
}
}
# Return the list
return $permList
}
В приведенном выше, каждое разрешение имеет следующие значения:
Perm Hexadecimal Binary Decimal
perm1 -> 0x00000001 -> 00000001 -> 1
perm2 -> 0x00000002 -> 00000010 -> 2
perm3 -> 0x00000004 -> 00000100 -> 4
perm4 -> 0x00000008 -> 00001000 -> 8
perm5 -> 0x00000010 -> 00010000 -> 16
perm6 -> 0x00000020 -> 00100000 -> 32
perm7 -> 0x00000040 -> 01000000 -> 64
perm8 -> 0x00000080 -> 10000000 -> 128
А конкретная комбинация разрешений будет иметь сумму отдельных разрешений. Например, если у кого-то есть и perm1, и perm4, их общие разрешения будут равны 9. Обратный будет использовать процедуру, описанную выше; у нас есть значение 9, и мы хотим знать, какие разрешения у этого человека. Таким образом, мы сделаем getPermList 9
и получим в результате: perm1 perm4
.
В двоичном коде 9 представляется как:
00001001
А индивидуальные разрешения perm1 и perm4 следующие:
00000001
00001000
Добавление двух (сложение чисел по вертикали) дает двоичное представление числа 9. Так что же здесь происходит?
Цикл (dict for
) сравнивает каждое значение dict с разрешением, для которого мы хотим детализацию:
perm1
Binary: 00001001 Decimal: 9
& 00000001 & 1
= 00000001 = 1
Поскольку результат больше 0, perm1 - это одно из разрешений, которое предоставляется разрешению с общим значением 9.
perm2
Binary: 00001001 Decimal: 9
& 00000010 & 2
= 00000000 = 0
Поскольку результат равен 0, perm2 не является одним из разрешений, которые предоставляются разрешению с общим значением 9. Цикл продолжается, и мы обнаруживаем, что единственный раз, когда он дает ненулевой результат, это perm4 :
perm4
Binary: 00001001 Decimal: 9
& 00001000 & 8
= 00001000 = 8
Вы можете прочитать, как поразрядно и работает по ссылке в Википедии, которую я имею в начале, но по сути, 1 & 1
дает 1, 1 & 0
, 0 & 1
и 0 & 0
все дают 0.
Если у кого-то есть все разрешения, у него будет значение разрешения 255 (1 + 2 + 4 + ... + 128), а если вы сделаете getPermList 255
, вы получите все разрешения, перечисленные в словарь.