Shembull: Bitwise shift operator me enumerated constants

Në programin vijues, fillimisht formohet një listë konstantash nëpërmes vlerës speciale iota, e cila by default gjeneron serinë e vlerave: 0, 1, 2, 3,… Mirëpo, në këtë rast, ne do ta manipulojmë vlerën e iota me bitwise shift operators. Me këtë do ta fitojmë një seri prej: 0, 1, 2, 4, pra 0, 2^0^, 2^1^ dhe 2^2^.

Qëllimi është që të fitohen vlera të kombinuara të 0, 1, 2 dhe 4, njëjtë sikurse e bën chmod në Linux. Kombinimin e dy vlerave në nivel të bitave do ta bëjmë me operatorin OR (|), me çka në fakt do të fitojmë numër.

Për shembull, operacioni OR ndaj Read (binar 100) dhe Write (binar 010), është 110, apo 6 në sistemin decimal. Kësisoj do të jemi në gjendje të ndërtojmë struktura degëzuese me if ose switch, ku do të mund t’i përdorim emrat e konstantave dhe operatorin OR për të verifikuar nëse përdoruesit i takon e drejta ekzekutimit, shkrimit apo leximit.

package main

import (
    "fmt"
)

const (
    isGuest = 1 << iota >> 1
    canExecute
    canWrite
    canRead
)

func main() {
    fmt.Printf("%03b = %v - No priviledges\n", isGuest, isGuest)
    fmt.Printf("%03b = %v - Execute\n", canExecute, canExecute)
    fmt.Printf("%03b = %v - Write\n", canWrite, canWrite)
    fmt.Printf("%03b = %v - Read\n", canRead, canRead)
    fmt.Printf("%03b = %v - Execute & Write\n", canExecute|canWrite, canExecute|canWrite)
    fmt.Printf("%03b = %v - Execute & Read\n", canExecute|canRead, canExecute|canRead)
    fmt.Printf("%03b = %v - Write & Read\n", canWrite|canRead, canWrite|canRead)
    fmt.Printf("%03b = %v - Execute & Write & Read\n", canExecute|canWrite|canRead, canExecute|canWrite|canRead)

    level := canRead | canWrite

    switch level {
    case isGuest:
        fmt.Println("You have no priviledges")
    case canRead:
        fmt.Println("You can Read")
    case canWrite:
        fmt.Println("You can Write")
    case canExecute:
        fmt.Println("You can Execute")
    case canWrite | canRead:
        fmt.Println("You can Read & Write")
    case canExecute | canRead:
        fmt.Println("You can Read & Execute")
    case canExecute | canWrite:
        fmt.Println("You can Write & Execute")
    case canExecute | canWrite | canRead:
        fmt.Println("You can Read, Write, Execute")
    }
}

https://play.golang.org/p/KtQ-XWX4mBg

Rezultati:

000 = 0 - No priviledges
001 = 1 - Execute
010 = 2 - Write
100 = 4 - Read
011 = 3 - Execute & Write
101 = 5 - Execute & Read
110 = 6 - Write & Read
111 = 7 - Execute & Write & Read
You can Read & Write

Bitwise left shift për 1 pozitë e ngrit iota-n në eksponentin për një më të lartë të numrit 2. Pra, nëse vlera binare është 10, bitwise left shift e bën 100. Bitwise right shift e bën të kundërtën – p.sh. numrin binar 100 e kthen në 10.

Meqenëse iota me bitwise left shift fiton vlerë fillestare 1, ndërsa ne dëshirojmë të fillojë nga zeroja (p.sh. për përdoruesit që s’kanë asnjë privilegj), atëherë rezultatit të bitwise left shift i bëjmë bitwise right shift, gjë që do të mundësojë që vlera e parë e iota të jetë zero, por vlerat në vijim të jenë eksponente të numrit 2. Pra, kjo është arsyeja e përdorimit të shprehjes:

    isGuest =1 << iota >> 1

e cila në vend të serisë: 0, 1, 2, 3,…, që do të fitohej me:

    isGuest = iota

apo serisë: 1, 2, 4, 8,…, që do të fitohej me:

    isGuest =1 << iota

na e gjeneron serinë: 0, 1, 2, 4,…, për çdo konstantë vijuese në listë.

Duke e përdorur serinë 0, 1, 2, 4, jemi të siguruar se nuk do të ketë dy kombinime me rezultat të njëjtë të dy apo tri vlerave të ndryshme, sepse në çfarëdo mënyre që t’i mbledhim këta numra, gjithmonë kemi rezultat unik për secilin kombinim.

I> Duhet të theksohet se operatori OR në këtë shembull nuk vepron si operator logjik sikurse bëjmë kur e përdorim me strukturën if, por bën operacion në nivel të bitave të vlerave, duke e fituar një vlerë të re numerike binare. Kur bëjmë caktime apo krahasime vlerash, në vend se direkt të përdorim vlerat numerike, ne përdorim emrat e konstantave dhe operatorin OR, sepse kështu e dimë se nuk do të gabojmë. Pra, nuk kemi nevojë të mbajmë në mend se privilegji për ekzekutim dhe lexim është 6, po thjeshtë shkruajmë:

variabli = canExecute|canRead

ndërsa Go, operacionin canExecute|canRead në mënyrë interne do ta shohë si numër 6, por kjo për neve nuk ka rëndësi, sepse edhe krahasimin do ta bëjmë në mënyrë të njëjtë, pa iu referuar numrit konkret:

if variabli == canExecute|canRead {
...
}
All Rights Reserved Theme by 404 THEME.