func(s *Stack)Push(e int)bool { if s.IsFull() { returnfalse } // 把盘子摞上去 s.container[s.top] = e // 下一个能摞盘子的位置 s.top++ returntrue }
func(s *Stack)Pop()(flag bool, ret int) { // 如果栈空了,你就无法拿到新盘子,所以flag此时为false if s.IsEmpty() { returnfalse, ret } // 取出盘子 ret = s.container[s.top-1] // 下一个能取盘子的位置 s.top-- returntrue, ret }
func(s *Stack)Push(e string)bool { if s.IsFull() { returnfalse } s.container[s.top] = e s.top++ returntrue }
func(s *Stack)Pop()(flag bool, ret string) { // 如果栈是空的,那么就不能继续 Pop 了 if s.IsEmpty() { returnfalse, ret } ret = s.container[s.top-1] s.top-- returntrue, ret }
funcexec( v interface{}, // value f interface{}, // valueを引数に実行するfunc )interface{} { fv := reflect.ValueOf(f) if fv.Kind() != reflect.Func{ panic("2'nd argument is not func.") } rv := reflect.ValueOf(v) return fv.Call([]reflect.Value{rv})[0] }
// 以下のように使える exec(5, func(i int)int{ return i * ( i + 1) }) exec("Tom", func(s string)string{ return"hello! " + s })
// 第一引数と、第二引数の引数の型が違うと、buildはできるが実行時にエラーが起きる exec("Tom", func(i int)int{ return i * ( i + 1) })
funcmain() { //うーん、かなりイマイチ s := "i lOVE gOLANG" sr := "" for _, x := range s { xs := string(x) u := strings.ToUpper(xs) l := strings.ToLower(xs) if u == xs { sr += l } elseif l == xs { sr += u } else { sr += xs } } fmt.Println(sr) }
sr := strings.NewReader(s) b := new(bytes.Buffer) r := transform.NewReader(sr, japanese.EUCJP.NewDecoder()) // sr -> Decoder io.Copy(b, r) // (sr->Decoder)->b fmt.Println(b.String()) }
type People struct { Name string Age int Height string Weight string }
funcmain() { s := `名前,年齢,身長,体重 Tanaka,31,190cm,97kg Suzuki,46,180cm,79kg Matsui,45,188cm,95kg ` r := csv.NewReader(strings.NewReader(s))
var p []People
for i := 0; ; i++ { record, err := r.Read() if err == io.EOF { break } if err != nil { log.Fatal(err) } if i == 0 { continue }
var people People for i, v := range record { switch i { case0: people.Name = v case1: people.Age, err = strconv.Atoi(v) if err != nil { log.Fatal(err) } case2: people.Height = v case3: people.Weight = v } } p = append(p, people) }
Basically, using laravel pipelines you can pass an object between several classes in a fluid way to perform any type of task and finally return the resulting value once all the “tasks” have been executed.
The most clear example about how pipelines works resides in one of the most used components of the framework itself. I’m talking about middlewares.
Middleware provide a convenient mechanism for filtering HTTP requests entering your application… This is how a basic middleware looks like:
1 2 3 4 5 6 7 8
<?php app(Pipeline::class) ->send($content) ->through($pipes) ->via(‘customMethodName’) // <---- This one :) ->then(function ($content) { return Post::create(['content' => $content]); });
These “middlewares” are in fact just pipes by where the request is going to be sent thru, in order to perform any needed task. Here you can check if the request is an HTTP request, a JSON request, if there is any user authenticated, etc.
If you take a quick look to the Illuminate\Foundation\Http\Kernel class, you’ll see how the middlewares are executed by using a new instance of the Pipeline class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
<?php /** * Send the given request through the middleware / router. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ protectedfunctionsendRequestThroughRouter($request) { $this->app->instance('request', $request); Facade::clearResolvedInstance('request'); $this->bootstrap(); return (new Pipeline($this->app)) ->send($request) ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) ->then($this->dispatchToRouter()); }
You can read in the code something like: a new pipeline that sends the request through a list of middlewares and then dispatch the router.
Don’t worry if this seems a little overwhelmed to you. Let’s try to clarify the concept with the follow example.
Working on a class that requires to run multiple tasks
Consider this situation. Let’s say you are building a forum where people can create threads and leave comments. But your client ask you to auto-remove tags or edit them on every piece of content when it’s created.
So this is what you are asked to do:
Replace link tags with plain text.
Replace bad words with “*”
Remove script tags entirely from the content
Probably you end up creating classes to handle each of these “tasks”.
Each “task” class should have a “handle” method to perform the action. Maybe it would be a good idea to have a contract to be implemented by each class:
<?php namespaceApp; useClosure; classRemoveBadWordsimplementsPipe { publicfunctionhandle($content, Closure$next) { // Here you perform the task and return the updated $content // to the next pipe return$next($content); } }
The method used to perform the task should receive two parameters, the first one would be the passable object, and the second one would be a closure where the object is going to be redirected to after running the last pipe.
You can use a custom method name instead of ‘handle’. Then you need to specify the method name to be used by the pipeline, like so
1 2 3 4 5 6 7 8
<?php app(Pipeline::class) ->send($content) ->through($pipes) ->via(‘customMethodName’) // <---- This one :) ->then(function ($content) { return Post::create(['content' => $content]); });
What happens at the end ?
What should happen here is that the post content is going to be modified by each one of the $pipes and at the end, this resulting content is going to be stored.
Remember, there are tons of ways you can approach this type of issues. What you decide to do it’s up to you. But it is good to know that you have this tool in your arsenal to be used if necessary. I hope this example gives you a better understanding of what these “laravel pipelines” are and how to use them. You can also take a look at api laravel documents if you want to know more about how this