Yanıtlar:
Sadece bir for döngüsü yazabilir ve yazmalısınız. Basit, açık kod Git yoludur.
for i := 1; i <= 10; i++ {
fmt.Println(i)
}
İşte şimdiye kadar önerilen iki yolu karşılaştırmak için bir program
import (
"fmt"
"github.com/bradfitz/iter"
)
func p(i int) {
fmt.Println(i)
}
func plain() {
for i := 0; i < 10; i++ {
p(i)
}
}
func with_iter() {
for i := range iter.N(10) {
p(i)
}
}
func main() {
plain()
with_iter()
}
Sökme oluşturmak için böyle derleyin
go build -gcflags -S iter.go
İşte sade (listeden olmayan talimatları kaldırdım)
kurmak
0035 (/home/ncw/Go/iter.go:14) MOVQ $0,AX
0036 (/home/ncw/Go/iter.go:14) JMP ,38
döngü
0037 (/home/ncw/Go/iter.go:14) INCQ ,AX
0038 (/home/ncw/Go/iter.go:14) CMPQ AX,$10
0039 (/home/ncw/Go/iter.go:14) JGE $0,45
0040 (/home/ncw/Go/iter.go:15) MOVQ AX,i+-8(SP)
0041 (/home/ncw/Go/iter.go:15) MOVQ AX,(SP)
0042 (/home/ncw/Go/iter.go:15) CALL ,p+0(SB)
0043 (/home/ncw/Go/iter.go:15) MOVQ i+-8(SP),AX
0044 (/home/ncw/Go/iter.go:14) JMP ,37
0045 (/home/ncw/Go/iter.go:17) RET ,
Ve işte with_iter
kurmak
0052 (/home/ncw/Go/iter.go:20) MOVQ $10,AX
0053 (/home/ncw/Go/iter.go:20) MOVQ $0,~r0+-24(SP)
0054 (/home/ncw/Go/iter.go:20) MOVQ $0,~r0+-16(SP)
0055 (/home/ncw/Go/iter.go:20) MOVQ $0,~r0+-8(SP)
0056 (/home/ncw/Go/iter.go:20) MOVQ $type.[]struct {}+0(SB),(SP)
0057 (/home/ncw/Go/iter.go:20) MOVQ AX,8(SP)
0058 (/home/ncw/Go/iter.go:20) MOVQ AX,16(SP)
0059 (/home/ncw/Go/iter.go:20) PCDATA $0,$48
0060 (/home/ncw/Go/iter.go:20) CALL ,runtime.makeslice+0(SB)
0061 (/home/ncw/Go/iter.go:20) PCDATA $0,$-1
0062 (/home/ncw/Go/iter.go:20) MOVQ 24(SP),DX
0063 (/home/ncw/Go/iter.go:20) MOVQ 32(SP),CX
0064 (/home/ncw/Go/iter.go:20) MOVQ 40(SP),AX
0065 (/home/ncw/Go/iter.go:20) MOVQ DX,~r0+-24(SP)
0066 (/home/ncw/Go/iter.go:20) MOVQ CX,~r0+-16(SP)
0067 (/home/ncw/Go/iter.go:20) MOVQ AX,~r0+-8(SP)
0068 (/home/ncw/Go/iter.go:20) MOVQ $0,AX
0069 (/home/ncw/Go/iter.go:20) LEAQ ~r0+-24(SP),BX
0070 (/home/ncw/Go/iter.go:20) MOVQ 8(BX),BP
0071 (/home/ncw/Go/iter.go:20) MOVQ BP,autotmp_0006+-32(SP)
0072 (/home/ncw/Go/iter.go:20) JMP ,74
döngü
0073 (/home/ncw/Go/iter.go:20) INCQ ,AX
0074 (/home/ncw/Go/iter.go:20) MOVQ autotmp_0006+-32(SP),BP
0075 (/home/ncw/Go/iter.go:20) CMPQ AX,BP
0076 (/home/ncw/Go/iter.go:20) JGE $0,82
0077 (/home/ncw/Go/iter.go:20) MOVQ AX,autotmp_0005+-40(SP)
0078 (/home/ncw/Go/iter.go:21) MOVQ AX,(SP)
0079 (/home/ncw/Go/iter.go:21) CALL ,p+0(SB)
0080 (/home/ncw/Go/iter.go:21) MOVQ autotmp_0005+-40(SP),AX
0081 (/home/ncw/Go/iter.go:20) JMP ,73
0082 (/home/ncw/Go/iter.go:23) RET ,
Böylece, kurulum aşamasında tamamen satır içi olmasına rağmen, iter çözümünün çok daha pahalı olduğunu görebilirsiniz. Döngü aşamasında döngüde fazladan bir talimat vardır, ancak bu çok da kötü değildir.
Ben döngü için basit kullanırdım.
runtime.makeslice
ve diğeri değil - bunun çok daha yavaş olacağını bilmek için bir kıyaslamaya ihtiyacım yok!
runtime.makeslice
, sıfır boyut tahsisi istiyorsanız, bellek ayırmayacak kadar zekidir. Ancak yukarıdakiler hala onu çağırıyor ve kıyaslamanıza göre makinemde 10nS daha uzun sürüyor.
Mark Mishyn tarafından dilim kullanılması önerildi, ancak değişmez yolla oluşturulan dizi kullanılabildiğinde ve daha kısa olduğunda dizi oluşturmak make
ve for
döndürülen dilimde kullanmak için bir neden yoktur.
for i := range [5]int{} {
fmt.Println(i)
}
for range [5]int{} {
5
burada bir değişmezdir ve çalışma zamanında belirlenemez.
iter , tamsayılar üzerinde yineleme yapmak için sözdizimsel olarak farklı bir yol sağlayan çok küçük bir pakettir.
for i := range iter.N(4) {
fmt.Println(i)
}
Rob Pike (Go'nun yazarı) eleştirdi :
Görünüşe göre, neredeyse her biri bir for döngüsü gibi bir şey yapmaktan kaçınmak için bir yol bulduğunda, çok uzun veya hantal hissettirdiğinden, sonuç neredeyse her zaman daha kısa olandan daha fazla tuş vuruşudur. [...] Bu "iyileştirmeler" getirmek tüm çılgın yükü bir kenara bırakıyor.
iter
çünkü sürüm aslında daha az tuş vuruşlarını kullanan range
ve iter
otomatik olarak tamamlayacaktır.
for
döngüler gittikleri gibi Unix'in birinci sınıf vatandaşı değil. Ayrıca, aksine for
, seq
standart çıktı akışları bir sayı dizisi. Bunları yinelemek veya istememek tüketiciye bağlıdır. for i in $(seq 1 10); do ... done
Shell'de yaygın olmasına rağmen , for döngüsü yapmanın sadece bir yolu, ki bu seq
da çok yaygın olsa da , çıktıyı tüketmenin tek yoludur .
i in range(10)
tam olarak aynı şekilde davranılacak şekilde oluşturulabileceğini düşünmüyor i := 0; i < 10; i++
.
Paketi kullanarak for
bir Go range
ifadesini bir ForClause ve bir Go ifadesiyle karşılaştırmak için bir karşılaştırma ölçütü iter
.
iter_test.go
package main
import (
"testing"
"github.com/bradfitz/iter"
)
const loops = 1e6
func BenchmarkForClause(b *testing.B) {
b.ReportAllocs()
j := 0
for i := 0; i < b.N; i++ {
for j = 0; j < loops; j++ {
j = j
}
}
_ = j
}
func BenchmarkRangeIter(b *testing.B) {
b.ReportAllocs()
j := 0
for i := 0; i < b.N; i++ {
for j = range iter.N(loops) {
j = j
}
}
_ = j
}
// It does not cause any allocations.
func N(n int) []struct{} {
return make([]struct{}, n)
}
func BenchmarkIterAllocs(b *testing.B) {
b.ReportAllocs()
var n []struct{}
for i := 0; i < b.N; i++ {
n = iter.N(loops)
}
_ = n
}
Çıktı:
$ go test -bench=. -run=.
testing: warning: no tests to run
PASS
BenchmarkForClause 2000 1260356 ns/op 0 B/op 0 allocs/op
BenchmarkRangeIter 2000 1257312 ns/op 0 B/op 0 allocs/op
BenchmarkIterAllocs 20000000 82.2 ns/op 0 B/op 0 allocs/op
ok so/test 7.026s
$
Bu dil özelliğinden yoksun olmanızla ilgili endişelerinizi kabul ederken, muhtemelen normal bir for
döngü kullanmak isteyeceksiniz . Ve muhtemelen daha fazla Go kodu yazarken düşündüğünüzden daha iyi olacaksınız.
Yazdığım bu iter paketi bir basit tarafından desteklenen, deyimsel - for
döner değerler üzerinde bu döngü chan int
- çabasıyla tasarım bulundu geliştirmek https://github.com/bradfitz/iter olması dikkat çekti edildiği, önbellek ve performans sorunlarının yanı sıra zeki, ancak garip ve sezgisel olmayan bir uygulama. Kendi sürümüm aynı şekilde çalışıyor:
package main
import (
"fmt"
"github.com/drgrib/iter"
)
func main() {
for i := range iter.N(10) {
fmt.Println(i)
}
}
Ancak, kıyaslama kanal kullanımının çok pahalı bir seçenek olduğunu ortaya koydu. iter_test.go
Kullanarak paketimden çalıştırılabilecek 3 yöntemin karşılaştırılması
go test -bench=. -run=.
performansının ne kadar zayıf olduğunu ölçüyor
BenchmarkForMany-4 5000 329956 ns/op 0 B/op 0 allocs/op
BenchmarkDrgribIterMany-4 5 229904527 ns/op 195 B/op 1 allocs/op
BenchmarkBradfitzIterMany-4 5000 337952 ns/op 0 B/op 0 allocs/op
BenchmarkFor10-4 500000000 3.27 ns/op 0 B/op 0 allocs/op
BenchmarkDrgribIter10-4 500000 2907 ns/op 96 B/op 1 allocs/op
BenchmarkBradfitzIter10-4 100000000 12.1 ns/op 0 B/op 0 allocs/op
Süreçte, bu karşılaştırma ölçütü, bradfitz
çözümün for
döngü boyutu için yerleşik maddeye kıyasla nasıl düşük performans gösterdiğini de gösterir 10
.
Kısacası, Python ve Ruby'de bulunanlar for
için basit bir sözdizimi sağlarken , yerleşik cümlenin performansını çoğaltmanın hiçbir yolu [0,n)
bulunamamıştır.
Bu utanç verici çünkü Go ekibinin derleyiciye basit bir kural eklemesi,
for i := range 10 {
fmt.Println(i)
}
ile aynı makine koduna for i := 0; i < 10; i++
.
Ancak, adil olmak iter.N
gerekirse, kendim yazdıktan sonra (ama kıyaslamadan önce), kullanabileceğim tüm yerleri görmek için yakın zamanda yazılmış bir programa geri döndüm. Aslında pek yoktu. Kodumun hayati olmayan bir bölümünde daha eksiksiz, varsayılan bir for
madde olmadan alabileceğim tek bir nokta vardı .
Bu, prensipte dil için büyük bir hayal kırıklığı gibi görünse de, tıpkı benim yaptığım gibi - aslında pratikte buna gerçekten ihtiyacınız olmadığını görebilirsiniz. Rob Pike'ın jenerikler için söylediği gibi, aslında bu özelliği düşündüğünüz kadar kaçırmayabilirsiniz.
Kullanmadan ve endeksler ya da başka bir şey olmadan bir aralıkta yineleme yapmak istiyorsanız, bu kod örneği benim için iyi çalıştı. Ek bir bildiriye gerek yok, hayır _
. Yine de performansı kontrol etmedim.
for range [N]int{} {
// Body...
}
PS: GoLang'ın ilk günü. Lütfen, yanlış bir yaklaşım olup olmadığını eleştirin.
non-constant array bound
Bana atıyor .
Ayrıca github.com/wushilin/stream adresine de bakabilirsiniz.
Java.util.stream kavramı gibi tembel bir dere.
// It doesn't really allocate the 10 elements.
stream1 := stream.Range(0, 10)
// Print each element.
stream1.Each(print)
// Add 3 to each element, but it is a lazy add.
// You only add when consume the stream
stream2 := stream1.Map(func(i int) int {
return i + 3
})
// Well, this consumes the stream => return sum of stream2.
stream2.Reduce(func(i, j int) int {
return i + j
})
// Create stream with 5 elements
stream3 := stream.Of(1, 2, 3, 4, 5)
// Create stream from array
stream4 := stream.FromArray(arrayInput)
// Filter stream3, keep only elements that is bigger than 2,
// and return the Sum, which is 12
stream3.Filter(func(i int) bool {
return i > 2
}).Sum()
Bu yardımcı olur umarım
package main
import "fmt"
func main() {
nums := []int{2, 3, 4}
for _, num := range nums {
fmt.Println(num, sum)
}
}
Golang'da Python'un aralık işlevini taklit eden bir paket yazdım:
Paket https://github.com/thedevsaddam/iter
package main
import (
"fmt"
"github.com/thedevsaddam/iter"
)
func main() {
// sequence: 0-9
for v := range iter.N(10) {
fmt.Printf("%d ", v)
}
fmt.Println()
// output: 0 1 2 3 4 5 6 7 8 9
// sequence: 5-9
for v := range iter.N(5, 10) {
fmt.Printf("%d ", v)
}
fmt.Println()
// output: 5 6 7 8 9
// sequence: 1-9, increment by 2
for v := range iter.N(5, 10, 2) {
fmt.Printf("%d ", v)
}
fmt.Println()
// output: 5 7 9
// sequence: a-e
for v := range iter.L('a', 'e') {
fmt.Printf("%s ", string(v))
}
fmt.Println()
// output: a b c d e
}
Not: Eğlenmek için yazdım! Btw, bazen yardımcı olabilir