Go genericを使用して関数の小バージョンを実装しましょう
もしかしてNodejs、Python 3、Rustなどの言語を使ったことがありますか?
これらの言語にはmap,reduce,filterに代表される反復器に関連するAPIが存在する.
少し大げさに言えば、コンパイラは現代プログラミング言語資格証と呼ばれ、多くの言語でサポートされている機能です.
では、なぜみんなが小さなモーターを導入するのでしょうか.
次の文でコードを作ってみてください.
上のコードを見るだけで、このコードがどのようなアルゴリズムを実現しているかを直感的に知ることができますか?
これらのコードは使用に慣れているので、迅速に分析できますが、コードを見るだけでは文の役割が一度に分かるわけではありません.
また,上記のコードはGoの出生欠点
GoはGenerickをサポートしていないため、ユーザ構造体をソートするには、上のコードに
ご覧のように、このコードは特にありませんが、ユーザーが直接実装する場合は、かなり面倒です.
特に最も問題があると考える部分はfor文の意味が不明確である.
私たちはすでに多くのfor文を見たことがあります.上のコードのfor文は実は簡単で、説明しにくいことはありませんが、これより長い条件があれば、このfor文がどんな目的で使われているのか分かりません.
では、上のコードと下のrustコードを比較してみましょう.student配列 コードの内容を小バージョンで読む前にその役割が理解できなかったfor文よりも、コードのみを使う意味が明確だと思います.
そのため、私は小さなプログラム関連のAPIが大好きで、できればいつでもそれを使用します.
したがって,実装されたイテレーションの使用は以下のようになる.
ただし、今後、より先進的なGenericサポートとMethod Genericをサポートすれば、以下のコードを記述することができます.
個人的には楽しみです.
現在、ジュネーブの限界により、上記のコードは実現できません.
正確には、
詳細については、go proposal : type-parameters #No-parameterized-methodsを参照してください.
残念なことに、今回のジェニーンリックは私の期待を100%満たすことができなかった.
しかし、その後もジュネーブの発展の可能性を非常に望んでいます.
特に言語の観点からジェニーリックを支持し始めたのは希望だったが...goroutineをアプレットAPIに統合した場合??
ウィジェットAPIは基本的に順序依存性がないため,goroutineによる並列処理成長が有望である.
大股で進むGo言語乾杯!
最後に、私が実現した奇形腫APIコードの最後の文章を完成します.
これらの言語にはmap,reduce,filterに代表される反復器に関連するAPIが存在する.
少し大げさに言えば、コンパイラは現代プログラミング言語資格証と呼ばれ、多くの言語でサポートされている機能です.
では、なぜみんなが小さなモーターを導入するのでしょうか.
次の文でコードを作ってみてください.
당신은 이름과, C 언어 시험점수, JAVA 언어 시험점수를 가지는 학생 배열을 가지고 있다.
여기서 학생 배열을 받아 학생들의 점수 평균을 측정한다
이후 평균이 90점 이상인 학생들만 가지고 정렬을 해야 한다.
goで作成すると、次のようになります.package main
import (
"fmt"
"sort"
)
type Student struct {
name string
cLanguage float32
javaLanguage float32
}
type StudentMean struct {
name string
mean float32
}
type ArrayStudentMean []StudentMean
func (a ArrayStudentMean) Len() int { return len(a) }
func (a ArrayStudentMean) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ArrayStudentMean) Less(i, j int) bool { return a[i].mean < a[j].mean }
func main() {
var students []Student = []Student{
{name: "나", cLanguage: 100, javaLanguage: 100},
{name: "철수", cLanguage: 90, javaLanguage: 80},
{name: "영희", cLanguage: 90, javaLanguage: 95},
}
//
var above90 = ArrayStudentMean(make([]StudentMean, 0, len(students)))
for _, student := range students {
var studentMean = StudentMean{
name: student.name,
mean: (student.cLanguage + student.javaLanguage) / 2,
}
if studentMean.mean >= 90 {
above90 = append(above90, studentMean)
}
}
sort.Sort(above90)
//
for _, data := range above90 {
fmt.Printf("%s : %f\n", data.name, data.mean)
}
}
わざと注釈をつけないで、上の説明とコードを見て、率直に考えてみましょう.上のコードを見るだけで、このコードがどのようなアルゴリズムを実現しているかを直感的に知ることができますか?
これらのコードは使用に慣れているので、迅速に分析できますが、コードを見るだけでは文の役割が一度に分かるわけではありません.
また,上記のコードはGoの出生欠点
sort.Interface
に関係している.GoはGenerickをサポートしていないため、ユーザ構造体をソートするには、上のコードに
ArrayStudentMean
と同じ配列タイプを作成し、Len
、Swap
およびLess
メソッドを直接実装する必要がある.ご覧のように、このコードは特にありませんが、ユーザーが直接実装する場合は、かなり面倒です.
特に最も問題があると考える部分はfor文の意味が不明確である.
私たちはすでに多くのfor文を見たことがあります.上のコードのfor文は実は簡単で、説明しにくいことはありませんが、これより長い条件があれば、このfor文がどんな目的で使われているのか分かりません.
では、上のコードと下のrustコードを比較してみましょう.
struct Student {
name: String,
cLanguage: f32,
javaLanguage: f32,
}
fn main() {
let students = vec![
Student {
name: "나".to_string(),
cLanguage: 100.,
javaLanguage: 100.,
},
Student {
name: "철수".to_string(),
cLanguage: 90.,
javaLanguage: 80.,
},
Student {
name: "영희".to_string(),
cLanguage: 90.,
javaLanguage: 95.,
},
];
let mut data = students
.into_iter()
.map(|student| {
(
student.name,
(student.cLanguage + student.javaLanguage) / 2.,
)
})
.filter(|(_, mean)| *mean >= 90.)
.collect::<Vec<_>>();
data.sort_by(|(_, a_mean), (_, b_mean)| a_mean.partial_cmp(b_mean).unwrap());
data.iter().for_each(|(name, mean)| {
println!("{} : {}", name, mean);
});
}
ほとんどの人はrust言語を知らないかもしれませんが、上のソースコードを理解するのに問題はありません.map
により平均を計算filter
90点以上のみ選択collect
平均90点以上sort_by
ソートfor_each
|を出力します.そのため、私は小さなプログラム関連のAPIが大好きで、できればいつでもそれを使用します.
したがって,実装されたイテレーションの使用は以下のようになる.
type Student struct {
name string
cLanguage float32
javaLanguage float32
}
type StudentMean struct {
name string
mean float32
}
func main() {
var students []Student = []Student{
{name: "나", cLanguage: 100, javaLanguage: 100},
{name: "철수", cLanguage: 90, javaLanguage: 80},
{name: "영희", cLanguage: 90, javaLanguage: 95},
}
ForEach(func(t StudentMean) { fmt.Printf("%s : %f\n", t.name, t.mean) })(
Sorted(func(a, b StudentMean) int {
if a.mean == b.mean {
return 0
} else if a.mean < b.mean {
return -1
} else {
return 1
}
})(
Filter(func(t StudentMean) bool { return t.mean >= 90 })(
Map(func(t Student) StudentMean {
return StudentMean{name: t.name, mean: (t.cLanguage + t.javaLanguage) / 2}
})(
FromArray(students),
),
),
),
)
}
残念なことに、GoはMethodGenerickを許可せず、上記のような不便な小バージョンしか使用できません.ただし、今後、より先進的なGenericサポートとMethod Genericをサポートすれば、以下のコードを記述することができます.
func main() {
var students []Student = []Student{
{name: "나", cLanguage: 100, javaLanguage: 100},
{name: "철수", cLanguage: 90, javaLanguage: 80},
{name: "영희", cLanguage: 90, javaLanguage: 95},
}
// 메서드 체이닝 방식의 이터레이터
FromArray(students)
.Map(func(t Student) StudentMean {
return StudentMean{name: t.name, mean: (t.cLanguage + t.javaLanguage) / 2}
})
.Filter(func(t StudentMean) bool { return t.mean >= 90 })
.Sorted(func(a, b StudentMean) int {
if a.mean == b.mean {
return 0
} else if a.mean < b.mean {
return -1
} else {
return 1
}
}),
.ForEach(func(t StudentMean) { fmt.Printf("%s : %f\n", t.name, t.mean) })
}
これからもっと活躍して、上のようにコードを書いたらどうなるのでしょうか.個人的には楽しみです.
現在、ジュネーブの限界により、上記のコードは実現できません.
正確には、
.Map
の方法だけでは実現できない.(残りは実施可能)詳細については、go proposal : type-parameters #No-parameterized-methodsを参照してください.
残念なことに、今回のジェニーンリックは私の期待を100%満たすことができなかった.
しかし、その後もジュネーブの発展の可能性を非常に望んでいます.
特に言語の観点からジェニーリックを支持し始めたのは希望だったが...goroutineをアプレットAPIに統合した場合??
ウィジェットAPIは基本的に順序依存性がないため,goroutineによる並列処理成長が有望である.
大股で進むGo言語乾杯!
最後に、私が実現した奇形腫APIコードの最後の文章を完成します.
// Lazy evaluation 기반
type Iter[T any] func() (T, bool)
// 배열을 Iterator 로 변환
func FromArray[T any](array []T) Iter[T] {
var index = -1
var end T
return func() (T, bool) {
if index+1 < len(array) {
index += 1
return array[index], true
}
return end, false
}
}
// fn함수에 따라 매개변수로 주어지는 Iterator를 필터링
func Filter[T any](fn func(T) bool) func(Iter[T]) Iter[T] {
return func(origin Iter[T]) Iter[T] {
var end T
return func() (T, bool) {
for data, ok := origin(); ok; data, ok = origin() {
if fn(data) {
return data, true
}
}
return end, false
}
}
}
// fn함수에 따라 매개변수로 주어지는 Iterator를 변환
func Map[T any, E any](fn func(T) E) func(Iter[T]) Iter[E] {
return func(origin Iter[T]) Iter[E] {
var end E
return func() (E, bool) {
for data, ok := origin(); ok; data, ok = origin() {
return fn(data), true
}
return end, false
}
}
}
// fn함수에 따라 매개변수로 주어지는 Iterator를 정렬
func Sorted[T any](fn func(a, b T) int) func(Iter[T]) Iter[T] {
return func(origin Iter[T]) Iter[T] {
var collect = Collect(origin)
var n = len(collect)
for i := 1; i < n; i++ {
j := i
for j > 0 {
if fn(collect[j-1], collect[j]) > 0 {
collect[j-1], collect[j] = collect[j], collect[j-1]
}
j = j - 1
}
}
return FromArray(collect)
}
}
// 매개변수로 주어지는 Iterator를 배열로 묶음
func Collect[T any](origin Iter[T]) []T {
var collect = make([]T, 0, 10)
for data, ok := origin(); ok; data, ok = origin() {
collect = append(collect, data)
}
return collect
}
// Iterator각 요소를 fn을 적용시켜 실행
func ForEach[T any](fn func(T)) func(Iter[T]) {
return func(origin Iter[T]) {
for data, ok := origin(); ok; data, ok = origin() {
fn(data)
}
}
}
Reference
この問題について(Go genericを使用して関数の小バージョンを実装しましょう), 我々は、より多くの情報をここで見つけました https://velog.io/@egoavara/Go-generic을-이용해-함수형-이터레이터를-구현해-보자テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol