goio icon indicating copy to clipboard operation
goio copied to clipboard

Discussion on how to use

Open wayddmldbzz opened this issue 1 year ago • 1 comments

1、First I have a struct

type KVBase struct {
	Index      int64  `json:"index"`
	Enable     bool   `json:"enable"`
	Key        string `json:"key"`
	Value      string `json:"value"`
}

2、If I have an array of this struct, I hope to do some processing on it and get a map, I can write like this

        var kvs []KVBase
	m := make(map[string]string)
	sort.Slice(kvs, func(i, j int) bool {
		return kvs[i].Index < kvs[j].Index
	})
	for _, kv := range kvs {
		if !kv.Enable {
			continue
		}
		m[kv.Key] = kv.Value
	}

3、If the same structure is put into java, I can write it like this, and the efficiency should be similar to the above, I think it's elegant

        @Data
        class KVBase {
            private int index;
            private String key;
            private String value;
            private boolean enable;
        }

        KVBase[] kvs = {};
        Map<String, String> m = Stream.of(kvs)
                                      .sorted(Comparator.comparing(kv -> kv.index < kv.index))
                                      .filter(kv -> !kv.enable)
                                      .map(kv -> Pair.of(kv.key, kv.value))
                                      .collect(Collectors.toMap(Pair::getKey, Pair::getValue));

4、I personally thought this was elegant so I was looking to see if there was something like this in Go, until I discovered this framework. I looked at the examples and found that the methods in them were not only very similar, so I tried to write them in Java.But unfortunately I just got the following code

        sort.Slice(headers, func(i, j int) bool {
		return headers[i].Index < headers[j].Index
	})
        stream_1 := stream.FromSlice(headers)
	stream_1 = stream.Filter(stream_1, func(h header) bool {
		if h.Enable {
			return true
		}
		return false
	})
	stream_2 := stream.Map(stream_1, func(h header) fun.Pair[string, string] {
		f := fun.Pair[string, string]{
			V1: h.Key,
			V2: h.Value,
		}
		return f
	})
	m := make(map[string]string)
	stream.Collect(stream_2, func(f fun.Pair[string, string]) error {
		m[f.V1] = f.V2
		return nil
	})

So I want to ask:

  1. Is this framework capable of doing the same as java? If so, could you please provide examples or where they appear?
  2. If not, is there a serious mistake in my writing method? How can I write it so that it can be almost as efficient as the first writing method? Please give an example.

wayddmldbzz avatar Oct 09 '23 12:10 wayddmldbzz

Hey, @wayddmldbzz, Thank you for your interest in this framework. Your stream-based Java-example looks nice. The Java DSL uses an important language feature. Stream interface approximately looks like this:

interface Stream<T> {
  <R> map(Function<T, R>)
  ...
}

Unfortunately, to my knowledge Go does not support this kind of interfaces. The only similar feature that I was able to find was to use plain functions that can take generic parameters:

func Map[T, R](Stream[T], func(T)R)

Hence, the nice Java-style DSL seems to be infeasible in the current version of Go.

Your code looks almost right. In order to make it nicer, I would make a small refactoring:

func isEnabled(h KVBase) bool {
  return h.Enabled
}

func toKeyValuePair(h KVBase) fun.Pair[string, string] {
  return fun.NewPair(h.Key, h.Value)
}

func Foo() {
        sort.Slice(headers, func(i, j int) bool {
		return headers[i].Index < headers[j].Index
	})
        headersStream := stream.FromSlice(headers)
	enabled := stream.Filter(headersStream, isEnabled)
	keyValues := stream.Map(enabled, toKeyValuePair)
	m := make(map[string]string)
	preserveKeyValue := func(f fun.Pair[string, string]) {
		m[f.V1] = f.V2
	}
	delayedStreamExecution := stream.ForEach(keyValues, preserveKeyValue)
        _, err := io.UnsafeRunSync(delayedStreamExecution)
       ...
}

Note that stream is lazy and needs UnsafeRunSync at the end.

Primetalk avatar Oct 09 '23 17:10 Primetalk