рдлрд╛рд╕реНрдЯрд░ рдЧреЛ-рдЗрдЯ-рд╕реНрдЯреНрд░реАрдВрдЧ рдЧреЛ рдХреЙрдиреИрдЯреЗрд╢рди рдЗрди рдЧреЛ


рдЖрдЬ рд╣рдо рдЧреЛ рдореЗрдВ 30% рдЫреЛрдЯреА рд▓рд╛рдЗрдиреЛрдВ рдХреА рдмреЙрдиреНрдбрд┐рдВрдЧ рдХреЛ рддреЗрдЬ рдХрд░реЗрдВрдЧреЗред рдФрд░ рдЗрд╕рдХреЗ рд▓рд┐рдП рд╣рдореЗрдВ рд╕реНрд╡рдпрдВ рдЧреЛ рдХреЛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрдЧреА, рдпрд╣ рд╕рдм рддреАрд╕рд░реЗ рдкрдХреНрд╖ рдХреЗ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ рд░реВрдк рдореЗрдВ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред


рдЙрд╕ рдХрдЯреМрддреА рдХреЗ рддрд╣рдд рдЬрд┐рд╕рдХрд╛ рдЖрдк рдЗрдВрддрдЬрд╛рд░ рдХрд░ рд░рд╣реЗ рд╣реИрдВ:


  • рддреБрд▓рдирд╛ + , strings.Builder рдФрд░ рджреЗрд╢реА рд╕рдВрдШрдирди рдХрд╛рд░реНрдп
  • рдЖрдВрддрд░рд┐рдХ рдкрдВрдХреНрддрд┐ рд╡рд┐рд╡рд░рдг рдкрд░ рдЬрд╛рдПрдВ
  • рдереЛрдбрд╝рд╛ рдЕрд╕реЗрдВрдмрд▓ рдХрд░реЗрдВ

рдЗрд╕ рд▓реЗрдЦ рдХреЛ CL123256 рдкрд░ рдЪрд░реНрдЪрд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдмрд╣рд╛рдирд╛ рднреА рдорд╛рдирд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ : рд░рдирдЯрд╛рдЗрдо, cmd / рд╕рдВрдХрд▓рди: concatstring2 рд╡рд┐рд╢реЗрд╖рдЬреНрдЮ ред рдЗрд╕ рдкрд░рд┐рд╡рд░реНрддрди рд╕реВрдЪреА рдореЗрдВ рд╕реБрдзрд╛рд░ рдХреЗ рд▓рд┐рдП рд╡рд┐рдЪрд╛рд░реЛрдВ рдХрд╛ рд╕реНрд╡рд╛рдЧрдд рд╣реИред


рддреБрд░рдВрдд рдкрд░рд┐рдгрд╛рдо


рдХрдВрдкрд╛рдЗрд▓рд░ рдХреЗ go tip (рдорд╛рд╕реНрдЯрд░) рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рд╕рд╛рде рддреБрд▓рдирд╛ рдХреА рдЧрдИ рдереАред рдЖрдк рдЧреЛ 1.5 рдХреЗ рдЖрд╕рдкрд╛рд╕ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдкрд░ рд╕рдорд╛рди рдкрд░рд┐рдгрд╛рдо рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред concatstrings рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рдЕрдВрддрд┐рдо рдорд╣рддреНрд╡рдкреВрд░реНрдг рдкрд░рд┐рд╡рд░реНрддрди CL3120: cmd / gc рдерд╛: рд╕реНрдЯреИрдХ рдкрд░ рдЧреИрд░-рдПрд╕реНрдХреЗрдк рд╕реНрдЯреНрд░рд┐рдВрдЧреНрд╕ рдХреЗ рд▓рд┐рдП рдмрдлрд╝рд░реНрд╕ рдЖрд╡рдВрдЯрд┐рдд рдХрд░реЗрдВ ред


 BenchmarkConcat2Operator-8 20000000 83.8 ns/op BenchmarkConcat2Builder-8 20000000 70.9 ns/op BenchmarkConcat2-8 20000000 62.1 ns/op BenchmarkConcat3Operator-8 20000000 104 ns/op BenchmarkConcat3Builder-8 20000000 89.9 ns/op BenchmarkConcat3-8 20000000 82.1 ns/op 

ConcatOperator + рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред
ConcatBuilder рд╕рд╣реА рдкреВрд░реНрд╡-рдЖрд╡рдВрдЯрди рдХреЗ рд╕рд╛рде ConcatBuilder рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред
Concat рдЙрд╕ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рдЗрд╕ рдХрд╣рд╛рдиреА рдХреЗ рд╣рд┐рд╕реНрд╕реЗ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд░рддреЗ рд╣реИрдВред


рдмреЗрдВрдЪрд╕реНрдЯреИрдЯ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рддреБрд▓рдирд╛:


 name old time/op new time/op delta Concat2-8 84.2ns ┬▒ 1% 62.7ns ┬▒ 2% -25.49% (p=0.000 n=9+10) Concat3-8 103ns ┬▒ 3% 83ns ┬▒ 4% -19.83% (p=0.000 n=10+9) 

GOARCH=AMD64 рддрд╣рдд рдХреЛрдбрд╛рдВрддрд░рдХ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдереЛрдбрд╝рд╛ рддреЗрдЬ рд╣реИ рдФрд░ рдЗрд╕рдореЗрдВ рдЕрддрд┐рд░рд┐рдХреНрдд рдЕрдиреБрдХреВрд▓рди рд╣реИ, рдЬреЛ рдмрд┐рд▓реНрдЯ-рдЗрди + рдСрдкрд░реЗрдЯрд░ рдореЗрдВ рдореМрдЬреВрдж рд╣реИ, рд▓реЗрдХрд┐рди рдиреАрдЪреЗ рдЙрд╕ рдкрд░ рдФрд░ рдЕрдзрд┐рдХ:


 name old time/op new time/op delta Concat2-8 84.2ns ┬▒ 1% 57.1ns ┬▒ 3% -32.20% (p=0.000 n=9+9) 

рд╣рдо рдЕрд╕реЗрдВрдмрд▓рд░ рдлрд╝рдВрдХреНрд╢рди рдХреЛ 100% рдкреНрд░рджрд░реНрд╢рди (рд╢реЗрд╖ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд╕рд╛рдкреЗрдХреНрд╖) рдХреЗ рд░реВрдк рдореЗрдВ рд▓реЗрдВрдЧреЗред


рд▓рдВрдмреА рд▓рд╛рдЗрдиреЛрдВ рдХреЗ рдкрд░рд┐рдгрд╛рдо README.md рдореЗрдВ рджреЗрдЦреЗ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВред рд╕реНрдЯреНрд░рд┐рдВрдЧ рдЬрд┐рддрдиреА рд▓рдВрдмреА рд╣реЛрдЧреА, рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рдмреАрдЪ рдХрд╛ рдЕрдВрддрд░ рдЙрддрдирд╛ рд╣реА рдХрдо рд╣реЛрдЧрд╛ред

рднреЛрд▓рд╛рдкрди


рд╕рдмрд╕реЗ рдЖрд╕рд╛рди рдЙрдкрд╛рдп рд╣реИ + рдСрдкрд░реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ред


рдЗрд╕ рдХрдерди рдХреЗ рд╢рдмреНрджрд╛рд░реНрде рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реИрдВ: рджреЛ рдкрдВрдХреНрддрд┐рдпрд╛рдБ рд▓реЗрдВ рдФрд░ рдПрдХ рдкрд░рд┐рдгрд╛рдо рд╕реНрдЯреНрд░рд┐рдВрдЧ рд▓реМрдЯрд╛рдПрдБ рдЬрд┐рд╕рдореЗрдВ рджреЛрдиреЛрдВ рд░реЗрдЦрд╛рдУрдВ рдХрд╛ рд╕рдВрдШрд╛рдд рд╣реЛред рдЗрд╕ рдмрд╛рдд рдХреА рдХреЛрдИ рдЧрд╛рд░рдВрдЯреА рдирд╣реАрдВ рд╣реИ рдХрд┐ рдПрдХ рдирдИ рд▓рд╛рдЗрди рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рдПрдЧреАред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдЦрд╛рд▓реА рд╕реНрдЯреНрд░рд┐рдВрдЧ рдФрд░ рдХрд┐рд╕реА рднреА рдЕрдиреНрдп рдХрд╛ рд╕рдВрдпреЛрдЬрди рд╣реИ, рддреЛ рд░рдирдЯрд╛рдЗрдо рдПрдХ рдЧреИрд░-рд░рд┐рдХреНрдд рддрд░реНрдХ рд▓реМрдЯрд╛ рд╕рдХрддрд╛ рд╣реИ, рдирдИ рдореЗрдореЛрд░реА рдХреЛ рдЖрд╡рдВрдЯрд┐рдд рдХрд░рдиреЗ рдФрд░ рд╡рд╣рд╛рдВ рдбреЗрдЯрд╛ рдХреЙрдкреА рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╕реЗ рдмрдЪрддрд╛ рд╣реИред


рд▓реЗрдХрд┐рди, рдЬреИрд╕рд╛ рдХрд┐ рд▓реЗрдЦ рдХреА рд╢реБрд░реБрдЖрдд рдореЗрдВ рдкрд░рд┐рдгрд╛рдореЛрдВ рд╕реЗ рджреЗрдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдпрд╣ рд╕рдмрд╕реЗ рдзреАрдорд╛ рддрд░реАрдХрд╛ рд╣реИред


 func concat2operator(x, y string) string { return x + y } 

рдкреНрд░рджрд░реНрд╢рди рд░реЗрдЯрд┐рдВрдЧ: 67.8% ред

strings.Builder


рдмрд╣реБрдд рд╕рдордп рдкрд╣рд▓реЗ рдирд╣реАрдВ, рдЧреЛ - рд╕реНрдЯреНрд░рд┐рдВрдЧреНрд╕ рдХреЗ рд▓рд┐рдП рдПрдХ рдирдпрд╛ рдкреНрд░рдХрд╛рд░ рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛ рдерд╛ред рдпрд╣ bytes.Buffer рдХрд╛ рдПрдХ рдПрдирд╛рд▓реЙрдЧ рд╣реИред bytes.Buffer , рд▓реЗрдХрд┐рди String() рд╡рд┐рдзрд┐ рдХреЛ рдХреЙрд▓ рдХрд░рддреЗ рд╕рдордп, рдореЗрдореЛрд░реА рдХреЛ рдлрд┐рд░ рд╕реЗ рдЖрд╡рдВрдЯрд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдбреЗрдЯрд╛ рдХреА рдкреНрд░рддрд┐рд▓рд┐рдкрд┐ рдирд╣реАрдВ рдмрдирд╛рдИ рдЬрд╛рддреА рд╣реИред


bytes.Buffer рд╡рд┐рдкрд░реАрддред bytes.Buffer , рдмрд┐рд▓реНрдбрд░ рдХреЗ рдкрд╛рд╕ рдПрдХ рдЫреЛрдЯреЗ рдмрдлрд░ рдХрд╛ рдЕрдиреБрдХреВрд▓рди рдирд╣реАрдВ рд╣реИ рдФрд░ рдЗрд╕рд▓рд┐рдП, рдкрд╣рд▓реЗ рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдЖрд╡рдВрдЯрд┐рдд рдореЗрдореЛрд░реАред рдпрджрд┐ рдЖрдк Grow рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдкреНрд░рджрд░реНрд╢рди bytes.Buffer рд╕реЗ рднреА рдмрджрддрд░ рд╣реЛрдЧрд╛ред bytes.Buffer ред рдЧреЛ 1.11 рдореЗрдВ рдХрдИ рд░реЗрдЬрд┐рд╕реНрдЯрд░ рдЗрд╕ рд╡рд┐рд╢реЗрд╖ рд╕реБрд╡рд┐рдзрд╛ рдХреЗ рдХрд╛рд░рдг рд╣реЛрддреЗ рд╣реИрдВ ( CL113235 рджреЗрдЦреЗрдВ)ред


рд╣рдорд╛рд░реЗ рдХреЛрдб рдореЗрдВ, рдкреНрд░рдпреЛрдЧ рдХреА рд╢реБрджреНрдзрддрд╛ рдХреЗ рд▓рд┐рдП, рд╣рдо рдЗрд╕ рддреНрд░реБрдЯрд┐ рд╕реЗ рдмрдЪреЗрдВрдЧреЗред


 func concat2builder(x, y string) string { var builder strings.Builder builder.Grow(len(x) + len(y)) //      builder.WriteString(x) builder.WriteString(y) return builder.String() } 

рдкреНрд░рджрд░реНрд╢рди рд░реЗрдЯрд┐рдВрдЧ: 80.5% (+12.7)ред

рдХреЙрдирдЯреИрдЯрди рдХреЗ рд▓рд┐рдП рдХреЛрдб рдЬрдирд░реЗрд╢рди


рдпрджрд┐ рд╣рдо рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐ рдХрдВрдкрд╛рдЗрд▓рд░ + рдСрдкрд░реЗрдЯрд░ рдХреЗ рд▓рд┐рдП рдХрд┐рд╕ рдХреЛрдб рдХреЛ рдЙрддреНрдкрдиреНрди рдХрд░рддрд╛ рд╣реИ, рддреЛ рд╣рдо concatstring2 , concatstring3 concatstring2 рдХреЛ рдХреЙрд▓ рдХрд░реЗрдВрдЧреЗ, рдФрд░ рдЗрд╕реА рддрд░рд╣ ( concatstring5 рд╕рдорд╛рд╡реЗрд╢реА рддрдХ)ред


 func concat2codegen(x, y) string { return x + y } // => CALL runtime.concatstring2(SB) func concat3codegen(x, y, z) string { return x + y + z } // => CALL runtime.concatstring3(SB) 

рд╕реНрд╡рдпрдВ рд░рдирдЯрд╛рдЗрдо / рд╕реНрдЯреНрд░рд┐рдВрдЧ рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВ:


 func concatstring2(buf *tmpBuf, a [2]string) string { return concatstrings(buf, a[:]) } func concatstring3(buf *tmpBuf, a [3]string) string { return concatstrings(buf, a[:]) } 

рдЗрд╕рд▓рд┐рдП, рдпрд╣ рдлрдВрдХреНрд╢рди concatstrings рд╕реАрдЦрдирд╛ concatstrings ред
рд╕реНрдкреЙрдЗрд▓рд░ рдХреЗ рдиреАрдЪреЗ рдПрдХ рдкреВрд░реА рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рдЙрдкрд▓рдмреНрдз рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣рд╛рдВ рдПрдХ рдЙрдЪреНрдЪ-рд╕реНрддрд░реАрдп рд╡рд┐рд╡рд░рдг рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ:


  1. buf рдкреИрд░рд╛рдореАрдЯрд░ nil рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдпрд╣ рдмрдлрд░ рд╕рдВрдХрд▓рдХ рджреНрд╡рд╛рд░рд╛ рдЖрд╡рдВрдЯрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдпрджрд┐ рд░реЗрдЦрд╛ рдЕрдкрдиреА рдкрд░рд┐рднрд╛рд╖рд╛ рд╕реЗ "рдмрдЪ" рдирд╣реАрдВ рдЬрд╛рддреА рд╣реИред рдпрджрд┐ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдлреНрд░реЗрдо рд╕реЗ рдЕрдзрд┐рдХ рд╕рдордп рддрдХ рд░рд╣рддреА рд╣реИ, рддреЛ рдпрд╣ рдмрдлрд░ рд╣рдореЗрд╢рд╛ nil (рдЬреИрд╕рд╛ рдХрд┐ рдЕрдХреНрд╕рд░ рд╣реЛрддрд╛ рд╣реИ)ред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдпрджрд┐ рдпрд╣ рдмрдлрд╝рд░ рдЙрдкрд▓рдмреНрдз рд╣реИ, рддреЛ рдкрд░рд┐рдгрд╛рдо рдХреЗ рдЖрдмрдВрдЯрди рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдВрднрд╡ рд╣реЛрдЧрд╛, рдЬрдм рдкрд░рд┐рдгрд╛рдо рдЗрд╕рдореЗрдВ рдЯреВрдЯрддрд╛ рд╣реИ (рдЗрд╕рдХрд╛ рдЖрдХрд╛рд░ 32 рдмрд╛рдЗрдЯреНрд╕ рд╣реИ)ред
  2. рдпрджрд┐ рдПрдХ рдХреЛ рдЫреЛрдбрд╝рдХрд░ рд╕рднреА рд▓рд╛рдЗрдиреЗрдВ рдЦрд╛рд▓реА рд╣реИрдВ, рддреЛ рдлрд╝рдВрдХреНрд╢рди рдЗрд╕ рд▓рд╛рдЗрди рдХреЛ рд╡рд╛рдкрд╕ рдХрд░ рджреЗрдЧрд╛ред рд▓реЗрдХрд┐рди рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ, рд╕реНрдЯреИрдХ рдкрд░ рдЪрдпрдирд┐рдд рд▓рд╛рдЗрдиреЛрдВ рдФрд░ рдЙрдирдХреЗ рдлреНрд░реЗрдо рдХреЛ рдЫреЛрдбрд╝рдХрд░ рдЗрд╕ рдЕрдиреБрдХреВрд▓рди рдХреЛ рдмрд╛рдпрдкрд╛рд╕ рдХрд░ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рддрд╛рдХрд┐ рдХреЙрд▓рд░ рдХреЛ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдореБрдХреНрдд рдореЗрдореЛрд░реА рдкреНрд░рд╛рдкреНрдд рди рд╣реЛред
  3. рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╕рднреА рд▓рд╛рдЗрдиреЛрдВ рдХреЛ рдирдИ рдореЗрдореЛрд░реА рдореЗрдВ рдХреЙрдкреА рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рд╕рдореНтАНрдорд┐рд▓рди рд╕рдорд╛рд░реЛрд╣ рдХреА рдкреВрд░реА рд╕реВрдЪреА
 // concatstrings implements a Go string concatenation x+y+z+... // The operands are passed in the slice a. // If buf != nil, the compiler has determined that the result does not // escape the calling function, so the string data can be stored in buf // if small enough. func concatstrings(buf *tmpBuf, a []string) string { idx := 0 l := 0 count := 0 for i, x := range a { n := len(x) if n == 0 { continue } if l+n < l { throw("string concatenation too long") } l += n count++ idx = i } if count == 0 { return "" } // If there is just one string and either it is not on the stack // or our result does not escape the calling frame (buf != nil), // then we can return that string directly. if count == 1 && (buf != nil || !stringDataOnStack(a[idx])) { return a[idx] } s, b := rawstringtmp(buf, l) for _, x := range a { copy(b, x) b = b[len(x):] } return s } 

рдпрд╣рд╛рдБ рд╣рдо рдПрдХ рд╕рд╛рде рдХрдИ рд╕реНрдерд╛рдиреЛрдВ рдХреЛ рджреЗрдЦрддреЗ рд╣реИрдВ рдЬрд┐рдиреНрд╣реЗрдВ рдХрд┐рд╕реА рд╡рд┐рд╢реЗрд╖ рдорд╛рдорд▓реЗ рдХреЗ рд▓рд┐рдП рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:


  • buf рд╕рдмрд╕реЗ рдЕрдзрд┐рдХ рдмрд╛рд░ рдЦрд╛рд▓реА рд╣реЛрддрд╛ рд╣реИред рдЬрдм рдХрдВрдкрд╛рдЗрд▓рд░ рдпрд╣ рд╕рд╛рдмрд┐рдд рдирд╣реАрдВ рдХрд░ рд╕рдХрд╛ рдХрд┐ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рд╕реНрдЯреИрдХ рдкрд░ рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рд╕реБрд░рдХреНрд╖рд┐рдд рд╣реИ, рддреЛ рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рдкреИрд░рд╛рдореАрдЯрд░ рдкрд╛рд╕ рдХрд░рдирд╛ рдФрд░ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдЕрдВрджрд░ nil рд▓рд┐рдП рдЗрд╕реЗ рдЬрд╛рдВрдЪрдирд╛ рдХреЗрд╡рд▓ рдУрд╡рд░рд╣реЗрдб рджреЗрддрд╛ рд╣реИред
  • len(a) == 2 рд╕рд╛рде рд╡рд┐рд╢реЗрд╖ рдорд╛рдорд▓реЗ рдХреЗ рд▓рд┐рдП len(a) == 2 рд╣рдореЗрдВ рдПрдХ рдЪрдХреНрд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ рдФрд░ рдЧрдгрдирд╛ рдХреЛ рд╕рд░рд▓ рдмрдирд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдФрд░ рдпрд╣ рд╕рдВрдШрдирди рдХрд╛ рд╕рдмрд╕реЗ рдЖрдо рд░реВрдк рд╣реИред

рд╕рдВрдШрдЯрди рдХреЗ рдЖрдБрдХрдбрд╝реЗ

рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддреЗ рд╕рдордп ./make.bash (рдЧреЛ рд╕рдВрдХрд▓рдХ рдФрд░ stdlib рдХрд╛ ./make.bash ) рд╣рдо рджреЛ рдСрдкрд░реЗрдВрдб рдХреЗ рд╕рд╛рде 445 рд╕рдВрдпреЛрдЬрди рджреЗрдЦрддреЗ рд╣реИрдВ:


  • 398 рдкрд░рд┐рдгрд╛рдо рднрд╛рдЧ рд░рд╣реЗ рд╣реИрдВред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╣рдорд╛рд░реА рд╡рд┐рд╢реЗрд╖рдЬреНрдЮрддрд╛ рд╕рдордЭ рдореЗрдВ рдЖрддреА рд╣реИред
  • 47 рдкрд░рд┐рдгрд╛рдо рдЖрдкрдХреЗ рдлреНрд░реЗрдо рдХреЛ рдирд╣реАрдВ рдЫреЛрдбрд╝рддреЗ рд╣реИрдВред

рджреЛ рддрд░реНрдХреЛрдВ рд╕реЗ рдХреБрд▓ 89% рд╕рдВрдШрдирди рдкрд╕реАрдирд╛ рдЕрдиреБрдХреВрд▓рди рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВред


go рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдХреЗ рд▓рд┐рдП, рд╣рдорд╛рд░реЗ рдкрд╛рд╕:


  • 501 рдХреЙрд▓ рдХреЙрдиреНрд╕реНрдЯреНрд░реЗрд╕реНрдЯрд┐рдВрдЧ 2
  • 194 рдХреЙрд▓ рдХреЙрдиреНрд╕реНрдЯреНрд░реЗрд╕реНрдЯрд┐рдВрдЧ 3
  • 55 рдХреЙрд▓ рдХреЙрдиреНрдЯреНрд░рд╛рд╕реНрдЯреНрд░рд┐рдВрдЧ 4

рд╕рднреА рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдХреЗ рд▓рд┐рдП рд╕рдВрд╕реНрдХрд░рдг


рд╡рд┐рд╢реЗрд╖рдЬреНрдЮрддрд╛ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдпрд╣ рдЬрд╛рдирдирд╛ рд╣реЛрдЧрд╛ рдХрд┐ рдЧреЛ рдореЗрдВ рд▓рд╛рдЗрдиреЛрдВ рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХреИрд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рджреНрд╡рд┐рдЖрдзрд╛рд░реА рд╕рдВрдЧрддрддрд╛ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ, рдЬрдмрдХрд┐ unsafe.Pointer рдмрд┐рдирд╛ рдХрд┐рд╕реА рдмрд▓рд┐рджрд╛рди рдХреЗ *byte рд╕рд╛рде рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред


 type stringStruct struct { str *byte len int } 

рджреВрд╕рд░рд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдирд┐рд╖реНрдХрд░реНрд╖ рдЬрд┐рд╕реЗ рд╣рдо рд░рдирдЯрд╛рдЗрдо рд╕реЗ рдЖрдХрд░реНрд╖рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ: рд▓рд╛рдЗрдиреЗрдВ рдЙрдирдХреЗ рдЬреАрд╡рди рдХреЛ рдкрд░рд╕реНрдкрд░ рд░реВрдк рд╕реЗ рд╢реБрд░реВ рдХрд░рддреА рд╣реИрдВред рдореЗрдореЛрд░реА рдХрд╛ рдПрдХ рдЯреБрдХрдбрд╝рд╛ рдЖрд╡рдВрдЯрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬрд┐рд╕реЗ []byte рджреНрд╡рд╛рд░рд╛ рд╕рдВрджрд░реНрднрд┐рдд рдХрд┐рдпрд╛ []byte , рдЬрд┐рд╕рдореЗрдВ рдирдИ рд▓рд╛рдЗрди рдХреА рд╕рд╛рдордЧреНрд░реА рд▓рд┐рдЦреА рдЬрд╛рддреА рд╣реИ, рдФрд░ рдЙрд╕рдХреЗ рдмрд╛рдж рд╣реА []byte рдЫреЛрдбрд╝ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдЬрд┐рд╕ рдореЗрдореЛрд░реА рдХреЛ рдЗрд╕реЗ рд╕рдВрджрд░реНрднрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЙрд╕реЗ stringStruct рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред


рдЬреЛ рд▓реЛрдЧ рдЕрдзрд┐рдХ рд╡рд┐рд╡рд░рдг рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рдЙрдирдХреЗ рд▓рд┐рдП rawstringtmp рдФрд░ rawstring рдХреЗ рдХрд╛рд░реНрдпреЛрдВ рдХрд╛ рдЕрдзреНрдпрдпрди рдХрд░рдиреЗ рдХрд╛ рд╕реБрдЭрд╛рд╡ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред


runtime.rawstring
 // rawstring allocates storage for a new string. The returned // string and byte slice both refer to the same storage. // The storage is not zeroed. Callers should use // b to set the string contents and then drop b. func rawstring(size int) (s string, b []byte) { p := mallocgc(uintptr(size), nil, false) stringStructOf(&s).str = p stringStructOf(&s).len = size *(*slice)(unsafe.Pointer(&b)) = slice{p, size, size} return } 

unsafe рдкреИрдХреЗрдЬ рдХреЗ рдЕрдВрдзреЗрд░реЗ рдкрдХреНрд╖ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рд╣рдо рд▓рдЧрднрдЧ рд╕рдорд╛рди рд░реВрдк рд╕реЗ рдХреНрд░реИрдВрдХ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:


 func concat2(x, y string) string { length := len(x) + len(y) if length == 0 { return "" } b := make([]byte, length) copy(b, x) copy(b[len(x):], y) return goString(&b[0], length) } 

рд╣рдо []byte рд╣рд╛рдЗрд▓рд╛рдЗрдЯ рдХрд░рддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рд╣рдо рдПрдХ рдирдИ рд▓рд╛рдЗрди рдХреА рд╕рд╛рдордЧреНрд░реА рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд░рддреЗ рд╣реИрдВред рддрдм рд╣рдо рдХреЗрд╡рд▓ рдЕрдкреЗрдХреНрд╖рд┐рдд рд░рдирдЯрд╛рдЗрдо рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХреЛ рд▓рд╛рдХрд░ рд▓рд╛рдЗрди рдХреЛ рдЕрдВрддрд┐рдо рд░реВрдк рджреЗ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕рдХреЗ рд▓рд┐рдП goString рдлрд╝рдВрдХреНрд╢рди рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ:


 func goString(ptr *byte, length int) string { s := stringStruct{str: ptr, len: length} return *(*string)(unsafe.Pointer(&s)) } 

рдкреНрд░рджрд░реНрд╢рди рд░реЗрдЯрд┐рдВрдЧ: 91.9% (+10.9)ред

AMD64 рд╕рдВрд╕реНрдХрд░рдг


рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдкрд┐рдЫрд▓реЗ рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ рдЦрд╛рд▓реА рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рд╕рд╛рде рд╕рдВрдЧрддрд┐ рдХреЗ рд▓рд┐рдП рдЕрдиреБрдХреВрд▓рди рдирд╣реАрдВ рд╣реИ, рдФрд░ рд╣рдо рд╕реАрдзреЗ рдореЗрдореЛрд░реА рдЖрд╡рдВрдЯрд┐рдд рдХрд░рдиреЗ рдореЗрдВ рдЕрд╕рдорд░реНрдерддрд╛ рдХреЗ рдХрд╛рд░рдг рдХрдИ рдЕрдирд╛рд╡рд╢реНрдпрдХ рдЧрдгрдирд╛ рднреА рдХрд░рддреЗ рд╣реИрдВ, рд╣рдореЗрдВ рдмрд╛рдЗрдЯ рд╕реНрд▓рд╛рдЗрд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред


рдЧреЛ рдЕрд╕реЗрдореНрдмрд▓рд░ рдХреА рдПрдХ рджрд┐рд▓рдЪрд╕реНрдк рд╡рд┐рд╢реЗрд╖рддрд╛ рдпрд╣ рд╣реИ рдХрд┐ рдпрд╣ рдЖрдкрдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЧреИрд░-рдирд┐рд░реНрдпрд╛рдд рдпреЛрдЧреНрдп рд░рдирдЯрд╛рдЗрдо рдлрд╝рдВрдХреНрд╢рдиред runtime┬╖mallocgc рдХреЙрд▓ рдХреЛ рд╣рдо рдЕрд╕реЗрдВрдмрд▓реА рдХреЛрдб рд╕реЗ рднреА рдХреЙрд▓ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рднрд▓реЗ рд╣реА рдпрд╣ runtime рдкреИрдХреЗрдЬ рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рди рд╣реЛред рд╣рдо рдЗрд╕ рд╕рдВрдкрддреНрддрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред


рд╣рдо рд╕реНрдЯреИрдХ рдореЗрдореЛрд░реА рд▓рд╛рдЗрдиреЛрдВ рдХреЗ рд╕реНрд╡рд╛рдорд┐рддреНрд╡ рдХреА рднреА рдЬрд╛рдВрдЪ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЬреЛ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк рддрд░реНрдХреЛрдВ рдореЗрдВ рд╕реЗ рдХрд┐рд╕реА рдПрдХ рдХреА рд╡рд╛рдкрд╕реА рдХреЛ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реБрд░рдХреНрд╖рд┐рдд рдмрдирд╛рддрд╛ рд╣реИред


рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рддрд░реНрдХреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ concat2("", "123") ред x рдПрдХ рдЦрд╛рд▓реА рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╣реИ, рдФрд░ рдпрджрд┐ y рд╕реНрдЯреИрдХ рдкрд░ рдЖрд╡рдВрдЯрд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рддреЛ рд╣рдо рдЗрд╕реЗ рд╕рдВрдШрдирди рдХреЗ рдкрд░рд┐рдгрд╛рдо рдХреЗ рд░реВрдк рдореЗрдВ рд╡рд╛рдкрд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред


 //; ,  x  y   stringStruct. //; CX - y.str. //; SI - y.len. maybe_return_y: //;      . MOVQ (TLS), AX //; *g CMPQ CX, (AX) JL return_y //;  y_str < g.stack.lo CMPQ CX, 8(AX) JGE return_y //;  y_str >= g.stack.hi JMP concatenate //; y  ,    return_y: MOVQ CX, ret+32(FP) //; stringStruct.len MOVQ SI, ret+40(FP) //; stringStruct.str RET 

MOVQ (TLS), AX * рдХреЛ рд░рдЬрд┐рд╕реНрдЯрд░ рдореЗрдВ рд▓реЗ MOVQ (TLS), AX ред рд╢реВрдиреНрдп рдСрдлрд╕реЗрдЯ рдкрд░ рдкрдврд╝рдиреЗ рд╕реЗ g.stack.lo рдлрд╝реАрд▓реНрдб g.stack.lo , рдФрд░ g.stack.hi 8 рд╡реАрдВ рдмрд╛рдЗрдЯ (64-рдмрд┐рдЯ рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдХреЗ рд▓рд┐рдП) рд╕реЗ рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИред


 type g struct { stack struct { lo uintptr // 0(AX) hi uintptr // 8(AX) } stackguard0 uintptr // 16(AX) stackguard1 uintptr // 24(AX) // ...   } 

concatenate рд╢рд░реАрд░ рд╕реНрдореГрддрд┐ рдХреЛ рдЖрд╡рдВрдЯрд┐рдд рдХрд░рддрд╛ рд╣реИ, рдЗрд╕реЗ рджреЛрдиреЛрдВ рд░реЗрдЦрд╛рдУрдВ рд╕реЗ рднрд░рддрд╛ рд╣реИ, рдФрд░ рдПрдХ рдирдИ рд░реЗрдЦрд╛ рджреЗрддрд╛ рд╣реИред


рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдкреВрд░реА рд╕реВрдЪреА
 #include "textflag.h" #include "funcdata.h" TEXT ┬╖Strings(SB), 0, $48-48 NO_LOCAL_POINTERS //    . MOVQ x+0(FP), DX MOVQ x+8(FP), DI MOVQ y+16(FP), CX MOVQ y+24(FP), SI TESTQ DI, DI JZ maybe_return_y // x -  ,   y TESTQ SI, SI JZ maybe_return_x // y -  ,   x concatenate: LEAQ (DI)(SI*1), R8 // len(x) + len(y) //     . MOVQ R8, 0(SP) MOVQ $0, 8(SP) MOVB $0, 16(SP) CALL runtime┬╖mallocgc(SB) MOVQ 24(SP), AX //     MOVQ AX, newstr-8(SP) //  x. MOVQ x+0(FP), DX MOVQ x+8(FP), DI MOVQ AX, 0(SP) MOVQ DX, 8(SP) MOVQ DI, 16(SP) CALL runtime┬╖memmove(SB) //  y   len(x). MOVQ x+8(FP), DI MOVQ y+16(FP), CX MOVQ y+24(FP), SI MOVQ newstr-8(SP), AX LEAQ (AX)(DI*1), BX MOVQ BX, 0(SP) MOVQ CX, 8(SP) MOVQ SI, 16(SP) CALL runtime┬╖memmove(SB) //   . MOVQ newstr-8(SP), AX MOVQ x+8(FP), R8 ADDQ y+24(FP), R8 MOVQ AX, ret+32(FP) MOVQ R8, ret+40(FP) RET maybe_return_y: //      . MOVQ (TLS), AX // *g CMPQ CX, (AX) JL return_y //  y_ptr < stk.lo CMPQ CX, 8(AX) JGE return_y //  y_ptr >= stk.hi JMP concatenate // y  ,    return_y: MOVQ CX, ret+32(FP) MOVQ SI, ret+40(FP) RET maybe_return_x: //      . MOVQ (TLS), AX // *g CMPQ DX, (AX) JL return_x //  x_ptr < stk.lo CMPQ DX, 8(AX) JGE return_x //  x_ptr >= stk.hi JMP concatenate // x  ,    return_x: MOVQ DX, ret+32(FP) MOVQ DI, ret+40(FP) RET 

рдпрджрд┐ рдЖрдк рдЗрд╕ рдХреЛрдб рдореЗрдВ NO_LOCAL_POINTERS рдХреА рдкреНрд░рдХреГрддрд┐ рдореЗрдВ рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВ, рддреЛ рдЖрдк asm рд╕реЗ рдХреЙрд▓рд┐рдВрдЧ рдЧреЛ рдлрд╝рдВрдХреНрд╢рди рдкрдврд╝ рд╕рдХрддреЗ рд╣реИрдВ ("рдШрд╛рддрдХ рддреНрд░реБрдЯрд┐: рд▓рд╛рдкрддрд╛ рд╕реНрдЯреИрдореНрдкрдореИрдк") ред


рдкреНрд░рджрд░реНрд╢рди рд░реЗрдЯрд┐рдВрдЧ: 100% (+8.6)ред

рдирд┐рд╖реНрдХрд░реНрд╖ рдореЗрдВ


рд╕рднреА рдХреЛрдб рдХреЛ рдХреЙрдиреИрдЯ рдкреИрдХреЗрдЬ рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рджрд╛рди рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред


рдХреНрдпрд╛ рджреБрдирд┐рдпрд╛ рдЗрд╕ рддрд░рд╣ рдХреЗ рддреНрд╡рд░рд┐рдд рд╕рдордЭреМрддреЗ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИ? рдХреМрди рдЬрд╛рдирддрд╛ рд╣реИред


рд▓реЗрдЦ рдХреА рд╢реБрд░реБрдЖрдд рдореЗрдВ, CL123256 рдХрд╛ рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рдЙрд╕рдХреЗ рдкрд╛рд╕ рдХрдИ рд╡рд┐рдХрд╛рд╕ рдкрде рд╣реИрдВ:


  1. рдЗрд╕ рдорд╛рдорд▓реЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рд╡рд┐рдзрддрд╛рдкреВрд░реНрдг рд╡рд┐рд╢реЗрд╖рдЬреНрдЮрддрд╛ рдЬрдм рдХрдВрдкрд╛рдЗрд▓рд░ рдПрдХ рдЕрд╕реНрдерд╛рдпреА рдмрдлрд░ рдЖрд╡рдВрдЯрд┐рдд рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдкреНрд░рддреНрдпреЗрдХ рдорд╛рдорд▓реЗ рдХреЗ рд▓рд┐рдП рдХрдо рд╡рд┐рдХрд╛рд╕ рд╣реЛрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдЕрдзрд┐рдХ рдкреНрд░рдХрд╛рд░ рдХреЗ рд╕рдВрдШрдирди рдХреЛ рдХрд╡рд░ рдХрд░рддрд╛ рд╣реИ рдФрд░ рд╡реНрдпрд╛рд╡рд╣рд╛рд░рд┐рдХ рд░реВрдк рд╕реЗ рдХреЛрдб (рдорд╢реАрди рдФрд░ рдЧреЛ рдХреЛрдб рджреЛрдиреЛрдВ) рдХреЗ рдЖрдХрд╛рд░ рдореЗрдВ рд╡реГрджреНрдзрд┐ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред
  2. рд╡рд┐рд╢реЗрд╖ рдорд╛рдорд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХ рд╡рд┐рд╢реЗрд╖рдЬреНрдЮрддрд╛ред рдЕрдзрд┐рдХ рд▓рд╛рдн, рд▓реЗрдХрд┐рди рдЕрдзрд┐рдХ рдорд╢реАрди рдХреЛрдб, рдЕрдиреБрджреЗрд╢ рдХреИрд╢ рдХреЛ рдиреБрдХрд╕рд╛рди рдкрд╣реБрдВрдЪрд╛ рд╕рдХрддрд╛ рд╣реИред
  3. рдкреНрд░рддреНрдпреЗрдХ рд╡рд┐рд╢реЗрд╖ рдорд╛рдорд▓реЗ рдФрд░ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдореЗрдореЛрд╡ рдХреЗ рд▓рд┐рдП, рдорд╢реАрди рдХреЛрдб рдХреЗ рдЯреЛрдВрд╕, рдЗрд╕ рддрд░рд╣ рд╕реЗ рдХреИрд╕реЗ рдЧреНрд▓рд┐рдмрдХ рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣рд╛рдБ рдореБрдЦреНрдп рд░реВрдк рд╕реЗ рд╕рдореАрдЪреАрдирддрд╛ рдХреЗ рдкреНрд░рд╢реНрди рдЙрдарддреЗ рд╣реИрдВред

рд╡рд░реНрддрдорд╛рди рдкреНрд░рд╕реНрддрд╛рд╡рд┐рдд рд╡рд┐рдХрд▓реНрдк рд╕реНрдЯреНрд░рд┐рдВрдЧреНрд╕ рдХреА рдПрдХ рдЬреЛрдбрд╝реА рдХреЗ рд╕рдорд╡рд╢рд░рдг рдХрд╛ рд╕рдмрд╕реЗ рдЖрдо рдФрд░ рд╕рд░рд▓ рдорд╛рдорд▓рд╛ рддреЗрдЬ рдХрд░рддрд╛ рд╣реИ (arity = 2)ред


рдпрджрд┐ рдЧреЛ рдЗрд╕ рдкрд░рд┐рд╡рд░реНрддрди рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рддреЛ рддреАрд╕рд░реЗ рдкрдХреНрд╖ рдХреЗ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ рд░реВрдк рдореЗрдВ рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╕рдВрдЪрд╛рд▓рди рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдХреЗ рддреБрд▓рдиреАрдп рддреНрд╡рд░рдг рдкреНрд░рд╛рдкреНрдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдХрдо рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ, рд╕реБрдВрджрд░ рдФрд░ рд╕реБрд░реБрдЪрд┐рдкреВрд░реНрдг, рд▓реЗрдХрд┐рди рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред

Source: https://habr.com/ru/post/hi417479/


All Articles