2017-10-08 61 views
7

Właśnie zacząłem przechodzić przez gotour i napotkałem pytanie dotyczące rozdziału domyślnego przekrojów.Wydłuż długość plasterka po lewej

package main 

import "fmt" 

func main() { 
    s := []int{2, 3, 5, 7, 11, 13} 

    s = s[1:4] 
    fmt.Println(s) // [3 5 7] 
    fmt.Println(len(s)) // 3 

    s = s[:4] 
    fmt.Println(s) // [3 5 7 11] 
    fmt.Println(len(s)) // 4 

} 

Mogę przedłużyć długość wycinka po prawej stronie, wybierając indeks większy lub równy poprzedniej długości wycinka. na przykład s[:4], więc mogę osiągnąć wpis 11. Ale kiedy używam s[-1:] do rozciągnięcia po lewej stronie i osiągnięcia wpisu 2, kompilator daje mi błąd invalid slice index -1 (index must be non-negative). Czy możliwe jest przedłużenie odcinka po lewej stronie, aby uzyskać wpis 2 po wykonaniu s=s[1:4]?

Odpowiedz

1

Po pierwsze, aby odpowiedzieć na to pytanie, nie, to nie jest możliwe użycie ujemnych indeksów lub dostępu do tych danych z wyjątkiem utrzymując kopię oryginalnego wycinka.

Jest to jednak interesujące pytanie, ponieważ wskazano tu niespójność, o którą prawdopodobnie chodziło bardziej. Jeśli zaczniesz z plasterkiem jak here:

a := []int{2, 3, 5, 7, 11, 13} 
fmt.Println(a,len(a),cap(a)) 

[2 3 5 7 11 13] 6 6

i wziąć kawałek tylko środkowym

b := a[1:2] 
fmt.Println(b,len(b),cap(b)) 

[3] 1 5

Nie wolno indeksów dostępowych w oryginalnym przeszłości danych, które plaster len, jak można się spodziewać:

fmt.Println(b[3]) 

panic: runtime error: index out of range

Nie wolno reslice zawierać te dane ponownie sprzed indeksu start:

d := b[-1:] 

invalid slice index -1 (index must be non-negative)

Ale wolno reslice zawierać te dane ponownie po len do cap , co jest trochę dziwne:

// This is beyond the length of b, you can't index those, 
// but you can access them by reslicing 
c := b[:5] 

[3 5 7 11 13] 5 5

jest to nieco niespójne, ponieważ większość innych operacji na danych wycinków jest ograniczona przez przesunięcie w danych i len, a nie ograniczenie i oryginalną długość danych. Jednak jest to wyraźnie określone w specyfikacji i jest prawdopodobnie tylko artefaktem, w jaki sposób plasterki reprezentują widok na oryginalnej macierzy, a nie zamierzoną decyzją projektową zapewniającą dostęp do tych danych. Byłoby miło, gdybyś mógł wrócić do oryginalnej pamięci, ponieważ wciąż jest w pamięci, ale wygląda na to, że możesz zobaczyć koniec tablicy tylko do czapki, a nie początek po tym, jak przeciąłeś raz.Z spec temat ograniczeń dotyczących indeksów krojenie:

For arrays or strings, the indices are in range if 0 <= low <= high <= len(a), otherwise they are out of range. For slices, the upper index bound is the slice capacity cap(a) rather than the length. A constant index must be non-negative and representable by a value of type int; for arrays or constant strings, constant indices must also be in range. If both indices are constant, they must satisfy low <= high. If the indices are out of range at run time, a run-time panic occurs.

Prawdopodobnie byłoby lepiej być bezpieczne i używać oryginalnego kawałek tworzyć różne poglądy na danych, zamiast polegać na tym zachowaniu.

6

Po utworzeniu nowego plasterka z drugiego indeksu w podstawowej tablicy, podobnie jak w przypadku s = s[1:4], utracono odniesienie do pierwszego elementu w podstawowej tablicy.

A ponieważ operator plasterka s[i:j] wymaga i >= 0, nie można już uzyskać dostępu do pierwszego elementu oryginalnej tablicy przez dalsze cięcie istniejącego plasterka.

Można zachować oryginalną tablicę wokół, jednakże:

func main() { 
    a := [...]int{2, 3, 5, 7, 11, 13} 

    s := a[1:4] 
    fmt.Println(s)  // [3 5 7] 
    fmt.Println(len(s)) // 3 

    s = s[:4] 
    fmt.Println(s)  // [3 5 7 11] 
    fmt.Println(len(s)) // 4 

    s = a[:] 
    fmt.Println(s) // [2 3 5 7 11 13] 
}