mirror of
https://github.com/google/styleguide.git
synced 2024-03-22 13:11:43 +08:00
Merge branch 'google:gh-pages' into gh-pages
This commit is contained in:
commit
888f2a9bcb
277
cppguide.html
277
cppguide.html
|
@ -21,8 +21,8 @@ this power brings with it complexity, which in turn can make
|
||||||
code more bug-prone and harder to read and maintain.</p>
|
code more bug-prone and harder to read and maintain.</p>
|
||||||
|
|
||||||
<p>The goal of this guide is to manage this complexity by
|
<p>The goal of this guide is to manage this complexity by
|
||||||
describing in detail the dos and don'ts of writing C++ code
|
describing in detail the dos and don'ts of writing C++
|
||||||
. These rules exist to
|
code. These rules exist to
|
||||||
keep the code base manageable while still allowing
|
keep the code base manageable while still allowing
|
||||||
coders to use C++ language features productively.</p>
|
coders to use C++ language features productively.</p>
|
||||||
|
|
||||||
|
@ -164,9 +164,8 @@ input.</p>
|
||||||
|
|
||||||
<h2 id="C++_Version">C++ Version</h2>
|
<h2 id="C++_Version">C++ Version</h2>
|
||||||
|
|
||||||
<p>Currently, code should target C++17, i.e., should not use C++2x
|
<p>Currently, code should target C++20, i.e., should not use C++23
|
||||||
features, with the exception of <a href="#Designated_initializers">designated
|
features. The C++ version targeted by this guide will advance
|
||||||
initializers</a>. The C++ version targeted by this guide will advance
|
|
||||||
(aggressively) over time.</p>
|
(aggressively) over time.</p>
|
||||||
|
|
||||||
|
|
||||||
|
@ -176,7 +175,7 @@ input.</p>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p>Consider portability to other environments before using features
|
<p>Consider portability to other environments before using features
|
||||||
from C++14 and C++17 in your project.</p>
|
from C++17 and C++20 in your project.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 id="Header_Files">Header Files</h2>
|
<h2 id="Header_Files">Header Files</h2>
|
||||||
|
@ -415,6 +414,18 @@ should be included as:</p>
|
||||||
<pre>#include "base/logging.h"
|
<pre>#include "base/logging.h"
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
<p>Headers should only be included using an angle-bracketed path if the library
|
||||||
|
requires you to do so. In particular, the following headers require angle
|
||||||
|
brackets:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>C and C++ standard library headers (e.g. <code><stdlib.h></code>
|
||||||
|
and <code><string></code>).</li>
|
||||||
|
<li>POSIX, Linux, and Windows system headers (e.g. <code><unistd.h></code>
|
||||||
|
and <code><windows.h></code>).</li>
|
||||||
|
<li>In rare cases, third_party libraries (e.g. <code><Python.h></code>).</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<p>In <code><var>dir/foo</var>.cc</code> or
|
<p>In <code><var>dir/foo</var>.cc</code> or
|
||||||
<code><var>dir/foo_test</var>.cc</code>, whose main
|
<code><var>dir/foo_test</var>.cc</code>, whose main
|
||||||
purpose is to implement or test the stuff in
|
purpose is to implement or test the stuff in
|
||||||
|
@ -426,9 +437,9 @@ as follows:</p>
|
||||||
|
|
||||||
<li>A blank line</li>
|
<li>A blank line</li>
|
||||||
|
|
||||||
<li>C system headers (more precisely: headers in angle brackets with the
|
<li>C system headers, and any other headers in angle brackets with the
|
||||||
<code>.h</code> extension), e.g., <code><unistd.h></code>,
|
<code>.h</code> extension, e.g., <code><unistd.h></code>,
|
||||||
<code><stdlib.h></code>.</li>
|
<code><stdlib.h></code>, <code><Python.h></code>.</li>
|
||||||
|
|
||||||
<li>A blank line</li>
|
<li>A blank line</li>
|
||||||
|
|
||||||
|
@ -664,9 +675,9 @@ namespace baz = ::foo::bar::baz;
|
||||||
|
|
||||||
<pre>// Shorten access to some commonly used names (in a .h file).
|
<pre>// Shorten access to some commonly used names (in a .h file).
|
||||||
namespace librarian {
|
namespace librarian {
|
||||||
namespace impl { // Internal, not part of the API.
|
namespace internal { // Internal, not part of the API.
|
||||||
namespace sidetable = ::pipeline_diagnostics::sidetable;
|
namespace sidetable = ::pipeline_diagnostics::sidetable;
|
||||||
} // namespace impl
|
} // namespace internal
|
||||||
|
|
||||||
inline void my_inline_function() {
|
inline void my_inline_function() {
|
||||||
// namespace alias local to a function (or method).
|
// namespace alias local to a function (or method).
|
||||||
|
@ -686,6 +697,11 @@ inline void my_inline_function() {
|
||||||
using ::absl::container_internal::ImplementationDetail;
|
using ::absl::container_internal::ImplementationDetail;
|
||||||
</pre>
|
</pre>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li><p>Single-line nested namespace declarations
|
||||||
|
|
||||||
|
are preferred in new code, but are not required.</p>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<a id="Unnamed_Namespaces_and_Static_Variables"></a>
|
<a id="Unnamed_Namespaces_and_Static_Variables"></a>
|
||||||
|
@ -932,7 +948,7 @@ the formal language of the C++ standard. It means that the initializing
|
||||||
expression is a constant expression, and if the object is initialized by a
|
expression is a constant expression, and if the object is initialized by a
|
||||||
constructor call, then the constructor must be specified as
|
constructor call, then the constructor must be specified as
|
||||||
<code>constexpr</code>, too:</p>
|
<code>constexpr</code>, too:</p>
|
||||||
<pre>struct Foo { constexpr Foo(int) {} };
|
<pre class="goodcode">struct Foo { constexpr Foo(int) {} };
|
||||||
|
|
||||||
int n = 5; // Fine, 5 is a constant expression.
|
int n = 5; // Fine, 5 is a constant expression.
|
||||||
Foo x(2); // Fine, 2 is a constant expression and the chosen constructor is constexpr.
|
Foo x(2); // Fine, 2 is a constant expression and the chosen constructor is constexpr.
|
||||||
|
@ -940,12 +956,8 @@ Foo a[] = { Foo(1), Foo(2), Foo(3) }; // Fine</pre>
|
||||||
|
|
||||||
<p>Constant initialization is always allowed. Constant initialization of
|
<p>Constant initialization is always allowed. Constant initialization of
|
||||||
static storage duration variables should be marked with <code>constexpr</code>
|
static storage duration variables should be marked with <code>constexpr</code>
|
||||||
or where possible the
|
or <code>constinit</code>.
|
||||||
|
Any non-local static storage
|
||||||
|
|
||||||
<a href="https://github.com/abseil/abseil-cpp/blob/03c1513538584f4a04d666be5eb469e3979febba/absl/base/attributes.h#L540">
|
|
||||||
<code>ABSL_CONST_INIT</code></a>
|
|
||||||
attribute. Any non-local static storage
|
|
||||||
duration variable that is not so marked should be presumed to have
|
duration variable that is not so marked should be presumed to have
|
||||||
dynamic initialization, and reviewed very carefully.</p>
|
dynamic initialization, and reviewed very carefully.</p>
|
||||||
|
|
||||||
|
@ -1017,10 +1029,8 @@ does not make an observable difference. For example:</p>
|
||||||
<p><code>thread_local</code> variables that aren't declared inside a function
|
<p><code>thread_local</code> variables that aren't declared inside a function
|
||||||
must be initialized with a true compile-time constant,
|
must be initialized with a true compile-time constant,
|
||||||
and this must be enforced by using the
|
and this must be enforced by using the
|
||||||
|
<a href="https://en.cppreference.com/w/cpp/language/constinit">
|
||||||
|
<code>constinit</code></a>
|
||||||
<a href="https://github.com/abseil/abseil-cpp/blob/master/absl/base/attributes.h">
|
|
||||||
<code>ABSL_CONST_INIT</code></a>
|
|
||||||
attribute. Prefer
|
attribute. Prefer
|
||||||
<code>thread_local</code> over other ways of defining thread-local data.</p>
|
<code>thread_local</code> over other ways of defining thread-local data.</p>
|
||||||
|
|
||||||
|
@ -1093,13 +1103,11 @@ get a particularly hard to diagnose use-after-free.</p>
|
||||||
initialized with a true compile-time constant (i.e., they must have no
|
initialized with a true compile-time constant (i.e., they must have no
|
||||||
dynamic initialization). To enforce this, <code>thread_local</code> variables
|
dynamic initialization). To enforce this, <code>thread_local</code> variables
|
||||||
at class or namespace scope must be annotated with
|
at class or namespace scope must be annotated with
|
||||||
|
<a href="https://en.cppreference.com/w/cpp/language/constinit">
|
||||||
|
<code>constinit</code></a>
|
||||||
<a href="https://github.com/abseil/abseil-cpp/blob/master/absl/base/attributes.h">
|
|
||||||
<code>ABSL_CONST_INIT</code></a>
|
|
||||||
(or <code>constexpr</code>, but that should be rare):</p>
|
(or <code>constexpr</code>, but that should be rare):</p>
|
||||||
|
|
||||||
<pre> ABSL_CONST_INIT thread_local Foo foo = ...;
|
<pre> constinit thread_local Foo foo = ...;
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p><code>thread_local</code> variables inside a function have no initialization
|
<p><code>thread_local</code> variables inside a function have no initialization
|
||||||
|
@ -1177,8 +1185,7 @@ for your code ,
|
||||||
terminating the program may be an appropriate error handling
|
terminating the program may be an appropriate error handling
|
||||||
response. Otherwise, consider a factory function
|
response. Otherwise, consider a factory function
|
||||||
or <code>Init()</code> method as described in
|
or <code>Init()</code> method as described in
|
||||||
<a href="https://abseil.io/tips/42">TotW #42</a>
|
<a href="https://abseil.io/tips/42">TotW #42</a>.
|
||||||
.
|
|
||||||
Avoid <code>Init()</code> methods on objects with
|
Avoid <code>Init()</code> methods on objects with
|
||||||
no other states that affect which public methods may be called
|
no other states that affect which public methods may be called
|
||||||
(semi-constructed objects of this form are particularly hard to work
|
(semi-constructed objects of this form are particularly hard to work
|
||||||
|
@ -1445,8 +1452,6 @@ by making their constructors protected, by declaring their destructors protected
|
||||||
or by giving them one or more pure virtual member functions. Prefer to avoid
|
or by giving them one or more pure virtual member functions. Prefer to avoid
|
||||||
deriving from concrete classes.</p>
|
deriving from concrete classes.</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3 id="Structs_vs._Classes">Structs vs. Classes</h3>
|
<h3 id="Structs_vs._Classes">Structs vs. Classes</h3>
|
||||||
|
|
||||||
<p>Use a <code>struct</code> only for passive objects that
|
<p>Use a <code>struct</code> only for passive objects that
|
||||||
|
@ -1466,9 +1471,9 @@ break those invariants. Constructors, destructors, and helper methods may
|
||||||
be present; however, these methods must not require or enforce any
|
be present; however, these methods must not require or enforce any
|
||||||
invariants.</p>
|
invariants.</p>
|
||||||
|
|
||||||
<p>If more functionality or invariants are required, a
|
<p>If more functionality or invariants are required, or struct has wide visibility and expected to
|
||||||
<code>class</code> is more appropriate. If in doubt, make
|
evolve, then a <code>class</code> is more appropriate. If in doubt, make it a <code>class</code>.
|
||||||
it a <code>class</code>.</p>
|
</p>
|
||||||
|
|
||||||
<p>For consistency with STL, you can use
|
<p>For consistency with STL, you can use
|
||||||
<code>struct</code> instead of <code>class</code> for
|
<code>struct</code> instead of <code>class</code> for
|
||||||
|
@ -1678,17 +1683,23 @@ definitions. If possible, avoid defining operators as templates,
|
||||||
because they must satisfy this rule for any possible template
|
because they must satisfy this rule for any possible template
|
||||||
arguments. If you define an operator, also define
|
arguments. If you define an operator, also define
|
||||||
any related operators that make sense, and make sure they
|
any related operators that make sense, and make sure they
|
||||||
are defined consistently. For example, if you overload
|
are defined consistently.</p>
|
||||||
<code><</code>, overload all the comparison operators,
|
|
||||||
and make sure <code><</code> and <code>></code> never
|
|
||||||
return true for the same arguments.</p>
|
|
||||||
|
|
||||||
<p>Prefer to define non-modifying binary operators as
|
<p>Prefer to define non-modifying binary operators as
|
||||||
non-member functions. If a binary operator is defined as a
|
non-member functions. If a binary operator is defined as a
|
||||||
class member, implicit conversions will apply to the
|
class member, implicit conversions will apply to the
|
||||||
right-hand argument, but not the left-hand one. It will
|
right-hand argument, but not the left-hand one. It will
|
||||||
confuse your users if <code>a < b</code> compiles but
|
confuse your users if <code>a + b</code> compiles but
|
||||||
<code>b < a</code> doesn't.</p>
|
<code>b + a</code> doesn't.</p>
|
||||||
|
|
||||||
|
<p>For a type <code>T</code> whose values can be compared for
|
||||||
|
equality, define a non-member <code>operator==</code> and document when
|
||||||
|
two values of type <code>T</code> are considered equal.
|
||||||
|
If there is a single obvious notion of when a value <code>t1</code>
|
||||||
|
of type <code>T</code> is less than another such value <code>t2</code> then
|
||||||
|
you may also define <code>operator<=></code>, which should be
|
||||||
|
consistent with <code>operator==</code>.
|
||||||
|
Prefer not to overload the other comparison and ordering operators.</p>
|
||||||
|
|
||||||
<p>Don't go out of your way to avoid defining operator
|
<p>Don't go out of your way to avoid defining operator
|
||||||
overloads. For example, prefer to define <code>==</code>,
|
overloads. For example, prefer to define <code>==</code>,
|
||||||
|
@ -1788,7 +1799,7 @@ improve readability, and often provide the same or better
|
||||||
performance.</p>
|
performance.</p>
|
||||||
|
|
||||||
<p>Prefer to return by value or, failing that, return by reference.
|
<p>Prefer to return by value or, failing that, return by reference.
|
||||||
Avoid returning a pointer unless it can be null.</p>
|
Avoid returning a raw pointer unless it can be null.</p>
|
||||||
|
|
||||||
<p>Parameters are either inputs to the function, outputs from the
|
<p>Parameters are either inputs to the function, outputs from the
|
||||||
function, or both. Non-optional input parameters should usually be values
|
function, or both. Non-optional input parameters should usually be values
|
||||||
|
@ -1802,10 +1813,10 @@ optional outputs and optional input/output parameters.</p>
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Avoid defining functions that require a <code>const</code> reference parameter
|
Avoid defining functions that require a reference parameter to outlive the call.
|
||||||
to outlive the call, because <code>const</code> reference parameters bind
|
In some cases reference parameters can bind to temporaries, leading to lifetime
|
||||||
to temporaries. Instead, find a way to eliminate the lifetime requirement
|
bugs. Instead, find a way to eliminate the lifetime requirement
|
||||||
(for example, by copying the parameter), or pass it by <code>const</code>
|
(for example, by copying the parameter), or pass retained parameters by
|
||||||
pointer and document the lifetime and non-null requirements.
|
pointer and document the lifetime and non-null requirements.
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
|
@ -2249,10 +2260,10 @@ qualifier to methods), except as follows:</p>
|
||||||
<li>You may use them to define pairs of overloads, such as one taking
|
<li>You may use them to define pairs of overloads, such as one taking
|
||||||
<code>Foo&&</code> and the other taking <code>const Foo&</code>.
|
<code>Foo&&</code> and the other taking <code>const Foo&</code>.
|
||||||
Usually the preferred solution is just to pass by value, but an overloaded
|
Usually the preferred solution is just to pass by value, but an overloaded
|
||||||
pair of functions sometimes yields better performance and is sometimes
|
pair of functions sometimes yields better performance, for example if the
|
||||||
necessary in generic code that needs to support a wide variety of types.
|
functions sometimes don't consume the input. As always: if you're writing
|
||||||
As always: if you're writing more complicated code for the sake of
|
more complicated code for the sake of performance, make sure you have evidence
|
||||||
performance, make sure you have evidence that it actually helps.</li>
|
that it actually helps.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h3 id="Friends">Friends</h3>
|
<h3 id="Friends">Friends</h3>
|
||||||
|
@ -2636,9 +2647,9 @@ casts when explicit type conversion is necessary.
|
||||||
including <code>void*</code>. Use this
|
including <code>void*</code>. Use this
|
||||||
only if you know what you are doing and you understand the aliasing
|
only if you know what you are doing and you understand the aliasing
|
||||||
issues. Also, consider dereferencing the pointer (without a cast) and
|
issues. Also, consider dereferencing the pointer (without a cast) and
|
||||||
using <code>absl::bit_cast</code> to cast the resulting value.</li>
|
using <code>std::bit_cast</code> to cast the resulting value.</li>
|
||||||
|
|
||||||
<li>Use <code>absl::bit_cast</code> to interpret the raw bits of a
|
<li>Use <code>std::bit_cast</code> to interpret the raw bits of a
|
||||||
value using a different type of the same size (a type pun), such as
|
value using a different type of the same size (a type pun), such as
|
||||||
interpreting the bits of a <code>double</code> as
|
interpreting the bits of a <code>double</code> as
|
||||||
<code>int64_t</code>.</li>
|
<code>int64_t</code>.</li>
|
||||||
|
@ -2874,10 +2885,13 @@ putting the "adjective" (<code>const</code>) before the
|
||||||
<code>const</code> first, we do not require it. But be
|
<code>const</code> first, we do not require it. But be
|
||||||
consistent with the code around you!</p>
|
consistent with the code around you!</p>
|
||||||
|
|
||||||
<h3 id="Use_of_constexpr">Use of constexpr</h3>
|
<h3 id="Use_of_constexpr">Use of constexpr, constinit, and consteval</h3>
|
||||||
|
|
||||||
<p>Use <code>constexpr</code> to define true
|
<p>Use <code>constexpr</code> to define true
|
||||||
constants or to ensure constant initialization.</p>
|
constants or to ensure constant initialization.
|
||||||
|
Use <code>constinit</code> to ensure constant
|
||||||
|
initialization for non-constant variables.
|
||||||
|
</p>
|
||||||
|
|
||||||
<p class="definition"></p>
|
<p class="definition"></p>
|
||||||
<p> Some variables can be declared <code>constexpr</code>
|
<p> Some variables can be declared <code>constexpr</code>
|
||||||
|
@ -2885,7 +2899,8 @@ to indicate the variables are true constants, i.e., fixed at
|
||||||
compilation/link time. Some functions and constructors
|
compilation/link time. Some functions and constructors
|
||||||
can be declared <code>constexpr</code> which enables them
|
can be declared <code>constexpr</code> which enables them
|
||||||
to be used in defining a <code>constexpr</code>
|
to be used in defining a <code>constexpr</code>
|
||||||
variable.</p>
|
variable. Functions can be declared <code>consteval</code>
|
||||||
|
to restrict their use to compile time.</p>
|
||||||
|
|
||||||
<p class="pros"></p>
|
<p class="pros"></p>
|
||||||
<p>Use of <code>constexpr</code> enables definition of
|
<p>Use of <code>constexpr</code> enables definition of
|
||||||
|
@ -2906,9 +2921,11 @@ in these definitions.</p>
|
||||||
robust specification of the constant parts of an
|
robust specification of the constant parts of an
|
||||||
interface. Use <code>constexpr</code> to specify true
|
interface. Use <code>constexpr</code> to specify true
|
||||||
constants and the functions that support their
|
constants and the functions that support their
|
||||||
definitions. Avoid complexifying function definitions to
|
definitions. <code>consteval</code> may be used for
|
||||||
|
code that must not be invoked at runtime.
|
||||||
|
Avoid complexifying function definitions to
|
||||||
enable their use with <code>constexpr</code>. Do not use
|
enable their use with <code>constexpr</code>. Do not use
|
||||||
<code>constexpr</code> to force inlining.</p>
|
<code>constexpr</code> or <code>consteval</code> to force inlining.</p>
|
||||||
|
|
||||||
<h3 id="Integer_Types">Integer Types</h3>
|
<h3 id="Integer_Types">Integer Types</h3>
|
||||||
|
|
||||||
|
@ -2948,7 +2965,9 @@ like <code>int16_t</code>, <code>uint32_t</code>,
|
||||||
<code>int64_t</code>, etc. You should always use
|
<code>int64_t</code>, etc. You should always use
|
||||||
those in preference to <code>short</code>, <code>unsigned
|
those in preference to <code>short</code>, <code>unsigned
|
||||||
long long</code> and the like, when you need a guarantee
|
long long</code> and the like, when you need a guarantee
|
||||||
on the size of an integer. Of the built-in integer types, only
|
on the size of an integer. Prefer to omit the <code>std::</code>
|
||||||
|
prefix for these types, as the extra 5 characters do
|
||||||
|
not merit the added clutter. Of the built-in integer types, only
|
||||||
<code>int</code> should be used. When appropriate, you
|
<code>int</code> should be used. When appropriate, you
|
||||||
are welcome to use standard type aliases like
|
are welcome to use standard type aliases like
|
||||||
<code>size_t</code> and <code>ptrdiff_t</code>.</p>
|
<code>size_t</code> and <code>ptrdiff_t</code>.</p>
|
||||||
|
@ -3148,7 +3167,6 @@ possible:</p>
|
||||||
<li>Prefer not using <code>##</code> to generate
|
<li>Prefer not using <code>##</code> to generate
|
||||||
function/class/variable names.</li>
|
function/class/variable names.</li>
|
||||||
|
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>Exporting macros from headers (i.e., defining them in a header
|
<p>Exporting macros from headers (i.e., defining them in a header
|
||||||
|
@ -3230,8 +3248,8 @@ auto c = b; // c is an int
|
||||||
auto d{42}; // d is an int, not a std::initializer_list<int>
|
auto d{42}; // d is an int, not a std::initializer_list<int>
|
||||||
</pre>
|
</pre>
|
||||||
<code>auto</code> can be qualified with <code>const</code>, and can be
|
<code>auto</code> can be qualified with <code>const</code>, and can be
|
||||||
used as part of a pointer or reference type, but it can't be used as a
|
used as part of a pointer or reference type, and (since C++17) as a
|
||||||
template argument. A rare variant of this syntax uses
|
non-type template argument. A rare variant of this syntax uses
|
||||||
<code>decltype(auto)</code> instead of <code>auto</code>, in which case
|
<code>decltype(auto)</code> instead of <code>auto</code>, in which case
|
||||||
the deduced type is the result of applying
|
the deduced type is the result of applying
|
||||||
<a href="https://en.cppreference.com/w/cpp/language/decltype"><code>decltype</code></a>
|
<a href="https://en.cppreference.com/w/cpp/language/decltype"><code>decltype</code></a>
|
||||||
|
@ -3525,8 +3543,8 @@ ordering of fields than the <code>Point</code> example above.</p>
|
||||||
|
|
||||||
<p class="cons"></p>
|
<p class="cons"></p>
|
||||||
<p>While designated initializers have long been part of the C standard and
|
<p>While designated initializers have long been part of the C standard and
|
||||||
supported by C++ compilers as an extension, only recently have they made it
|
supported by C++ compilers as an extension, they were not supported by
|
||||||
into the C++ standard, being added as part of C++20.</p>
|
C++ prior to C++20.</p>
|
||||||
|
|
||||||
<p>The rules in the C++ standard are stricter than in C and compiler extensions,
|
<p>The rules in the C++ standard are stricter than in C and compiler extensions,
|
||||||
requiring that the designated initializers appear in the same order as the
|
requiring that the designated initializers appear in the same order as the
|
||||||
|
@ -3768,6 +3786,113 @@ error messages are part of your user interface, and your code should
|
||||||
be tweaked as necessary so that the error messages are understandable
|
be tweaked as necessary so that the error messages are understandable
|
||||||
and actionable from a user point of view.</p>
|
and actionable from a user point of view.</p>
|
||||||
|
|
||||||
|
<h3 id="Concepts">Concepts and Constraints</h3>
|
||||||
|
|
||||||
|
<p>Use concepts sparingly.
|
||||||
|
In general, concepts and constraints should only be used in cases
|
||||||
|
where templates would have been used prior to C++20.
|
||||||
|
Avoid introducing new concepts in headers,
|
||||||
|
unless the headers are marked as internal to the library.
|
||||||
|
Do not define concepts that are not enforced by the compiler.
|
||||||
|
Prefer constraints over template metaprogramming, and
|
||||||
|
avoid the <code>template<<i>Concept</i> T></code> syntax;
|
||||||
|
instead, use the <code>requires(<i>Concept<T></i>)</code>
|
||||||
|
syntax.</p>
|
||||||
|
|
||||||
|
<p class="definition"></p>
|
||||||
|
<p>The <code>concept</code> keyword is a new mechanism for defining
|
||||||
|
requirements (such as type traits or interface specifications)
|
||||||
|
for a template parameter.
|
||||||
|
The <code>requires</code> keyword provides mechanisms for placing
|
||||||
|
anonymous constraints on templates and verifying that constraints
|
||||||
|
are satisfied at compile time.
|
||||||
|
Concepts and constraints are often used together, but can be
|
||||||
|
also used independently.</p>
|
||||||
|
|
||||||
|
<p class="pros"></p>
|
||||||
|
<ul>
|
||||||
|
<li>Concepts allow the compiler to generate much better error
|
||||||
|
messages when templates are involved, which can reduce confusion
|
||||||
|
and significantly improve the development experience.</li>
|
||||||
|
<li>Concepts can reduce the boilerplate necessary for defining
|
||||||
|
and using compile-time constraints, often increasing the clarity
|
||||||
|
of the resulting code.</li>
|
||||||
|
<li>Constraints provide some capabilities that are difficult to
|
||||||
|
achieve with templates and SFINAE techniques.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p class="cons"></p>
|
||||||
|
<ul>
|
||||||
|
<li>As with templates, concepts can make code significantly more
|
||||||
|
complex and difficult to understand.</li>
|
||||||
|
<li>Concept syntax can be confusing to readers, as concepts
|
||||||
|
appear similar to class types at their usage sites.</li>
|
||||||
|
<li>Concepts, especially at API boundaries, increase code
|
||||||
|
coupling, rigidity, and ossification.</li>
|
||||||
|
<li>Concepts and constraints can replicate logic from a function
|
||||||
|
body, resulting in code duplication and increased maintenance
|
||||||
|
costs.</li>
|
||||||
|
<li>Concepts muddy the source of truth for their underlying
|
||||||
|
contracts, as they are standalone named entities that can be
|
||||||
|
utilized in multiple locations, all of which evolve separately
|
||||||
|
from each other.
|
||||||
|
This can cause the stated and implied requirements to diverge
|
||||||
|
over time.</li>
|
||||||
|
<li>Concepts and constraints affect overload resolution in novel
|
||||||
|
and non-obvious ways.</li>
|
||||||
|
<li>As with SFINAE, constraints make it harder to refactor code
|
||||||
|
at scale.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p class="decision"></p>
|
||||||
|
<p>Predefined concepts in the standard library should be
|
||||||
|
preferred to type traits, when equivalent ones exist.
|
||||||
|
(e.g., if <code>std::is_integral_v</code> would have been used
|
||||||
|
before C++20, then <code>std::integral</code> should be used in
|
||||||
|
C++20 code.)
|
||||||
|
Similarly, prefer modern constraint syntax
|
||||||
|
(via <code>requires(<i>Condition</i>)</code>).
|
||||||
|
Avoid legacy template metaprogramming constructs
|
||||||
|
(such as <code>std::enable_if<<i>Condition</i>></code>)
|
||||||
|
as well as the <code>template<<i>Concept</i> T></code>
|
||||||
|
syntax.</p>
|
||||||
|
|
||||||
|
<p>Do not manually re-implement any existing concepts or traits.
|
||||||
|
For example, use
|
||||||
|
<code>requires(std::default_initializable<T>)</code>
|
||||||
|
instead of
|
||||||
|
<code>requires(requires { T v; })</code>
|
||||||
|
or the like.
|
||||||
|
|
||||||
|
</p><p>New <code>concept</code> declarations should be rare, and only
|
||||||
|
defined internally within a library, such that they are not
|
||||||
|
exposed at API boundaries.
|
||||||
|
More generally, do not use concepts or constraints in cases where
|
||||||
|
you wouldn't use their legacy template equivalents in C++17.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>Do not define concepts that duplicate the function body,
|
||||||
|
or impose requirements that would be insignificant or obvious
|
||||||
|
from reading the body of the code or the resulting error messages.
|
||||||
|
For example, avoid the following:
|
||||||
|
</p><pre class="badcode">template <typename T> // Bad - redundant with negligible benefit
|
||||||
|
concept Addable = std::copyable<T> && requires(T a, T b) { a + b; };
|
||||||
|
template <Addable T>
|
||||||
|
T Add(T x, T y, T z) { return x + y + z; }
|
||||||
|
</pre>
|
||||||
|
Instead, prefer to leave code as an ordinary template unless
|
||||||
|
you can demonstrate that concepts result in significant
|
||||||
|
improvement for that particular case, such as in the resulting
|
||||||
|
error messages for a deeply nested or non-obvious
|
||||||
|
requirement.
|
||||||
|
|
||||||
|
<p>Concepts should be statically verifiable by the compiler.
|
||||||
|
Do not use any concept whose primary benefits would come from a
|
||||||
|
semantic (or otherwise unenforced) constraint.
|
||||||
|
Requirements that are unenforced at compile time should instead
|
||||||
|
be imposed via other mechanisms such as comments, assertions,
|
||||||
|
or tests.</p>
|
||||||
|
|
||||||
<h3 id="Boost">Boost</h3>
|
<h3 id="Boost">Boost</h3>
|
||||||
|
|
||||||
<p>Use only approved libraries from the Boost library
|
<p>Use only approved libraries from the Boost library
|
||||||
|
@ -3955,9 +4080,10 @@ guide, the following C++ features may not be used:</p>
|
||||||
|
|
||||||
<p class="definition"></p>
|
<p class="definition"></p>
|
||||||
<p>There are several ways to create names that are aliases of other entities:</p>
|
<p>There are several ways to create names that are aliases of other entities:</p>
|
||||||
<pre>typedef Foo Bar;
|
<pre>using Bar = Foo;
|
||||||
using Bar = Foo;
|
typedef Foo Bar; // But prefer `using` in C++ code.
|
||||||
using other_namespace::Foo;
|
using ::other_namespace::Foo;
|
||||||
|
using enum MyEnumType; // Creates aliases for all enumerators in MyEnumType.
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>In new code, <code>using</code> is preferable to <code>typedef</code>,
|
<p>In new code, <code>using</code> is preferable to <code>typedef</code>,
|
||||||
|
@ -4245,6 +4371,10 @@ using PropertiesMap = hash_map<UrlTableProperties *, std::string>;
|
||||||
enum class UrlTableError { ...
|
enum class UrlTableError { ...
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
<h3 id="Concept_Names">Concept Names</h3>
|
||||||
|
|
||||||
|
Concept names follow the same rules as <a href="#Type_Names">type names</a>.
|
||||||
|
|
||||||
<h3 id="Variable_Names">Variable Names</h3>
|
<h3 id="Variable_Names">Variable Names</h3>
|
||||||
|
|
||||||
<p>The names of variables (including function parameters) and data members are
|
<p>The names of variables (including function parameters) and data members are
|
||||||
|
@ -4308,9 +4438,10 @@ const int kAndroid8_0_0 = 24; // Android 8.0.0
|
||||||
|
|
||||||
<p>All such variables with static storage duration (i.e., statics and globals,
|
<p>All such variables with static storage duration (i.e., statics and globals,
|
||||||
see <a href="http://en.cppreference.com/w/cpp/language/storage_duration#Storage_duration">
|
see <a href="http://en.cppreference.com/w/cpp/language/storage_duration#Storage_duration">
|
||||||
Storage Duration</a> for details) should be named this way. This
|
Storage Duration</a> for details) should be named this way, including those in templates where
|
||||||
convention is optional for variables of other storage classes, e.g., automatic
|
different instantiations of the template may have different values. This convention is optional for
|
||||||
variables; otherwise the usual variable naming rules apply. For example:</p>
|
variables of other storage classes, e.g., automatic variables; otherwise the usual variable naming
|
||||||
|
rules apply. For example:</p>
|
||||||
|
|
||||||
<pre>void ComputeFoo(absl::string_view suffix) {
|
<pre>void ComputeFoo(absl::string_view suffix) {
|
||||||
// Either of these is acceptable.
|
// Either of these is acceptable.
|
||||||
|
@ -4515,7 +4646,7 @@ author line, consider deleting the author line.
|
||||||
New files should usually not contain copyright notice or
|
New files should usually not contain copyright notice or
|
||||||
author line.</p>
|
author line.</p>
|
||||||
|
|
||||||
<h3 id="Class_Comments">Class Comments</h3>
|
<h3 id="Class_Comments">Struct and Class Comments</h3>
|
||||||
|
|
||||||
<p>Every non-obvious class or struct declaration should have an
|
<p>Every non-obvious class or struct declaration should have an
|
||||||
accompanying comment that describes what it is for and how it should
|
accompanying comment that describes what it is for and how it should
|
||||||
|
@ -4532,6 +4663,8 @@ class GargantuanTableIterator {
|
||||||
};
|
};
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
<h4 id="Class_Comments_Details">Class Comments</h4>
|
||||||
|
|
||||||
<p>The class comment should provide the reader with enough information to know
|
<p>The class comment should provide the reader with enough information to know
|
||||||
how and when to use the class, as well as any additional considerations
|
how and when to use the class, as well as any additional considerations
|
||||||
necessary to correctly use the class. Document the synchronization assumptions
|
necessary to correctly use the class. Document the synchronization assumptions
|
||||||
|
@ -4925,7 +5058,8 @@ if included in the source as straight UTF-8.</p>
|
||||||
<p>When possible, avoid the <code>u8</code> prefix.
|
<p>When possible, avoid the <code>u8</code> prefix.
|
||||||
It has significantly different semantics starting in C++20
|
It has significantly different semantics starting in C++20
|
||||||
than in C++17, producing arrays of <code>char8_t</code>
|
than in C++17, producing arrays of <code>char8_t</code>
|
||||||
rather than <code>char</code>.
|
rather than <code>char</code>, and will change again in C++23.
|
||||||
|
|
||||||
|
|
||||||
</p><p>You shouldn't use <code>char16_t</code> and
|
</p><p>You shouldn't use <code>char16_t</code> and
|
||||||
<code>char32_t</code> character types, since they're for
|
<code>char32_t</code> character types, since they're for
|
||||||
|
@ -5091,7 +5225,8 @@ double d = 1248e6;
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<pre class="goodcode">float f = 1.0f;
|
<pre class="goodcode">float f = 1.0f;
|
||||||
float f2 = 1; // Also OK
|
float f2 = 1.0; // Also OK
|
||||||
|
float f3 = 1; // Also OK
|
||||||
long double ld = -0.5L;
|
long double ld = -0.5L;
|
||||||
double d = 1248.0e6;
|
double d = 1248.0e6;
|
||||||
</pre>
|
</pre>
|
||||||
|
|
|
@ -597,7 +597,11 @@ to have them in the same package.
|
||||||
Code within a package can access unexported identifiers in the package. If you
|
Code within a package can access unexported identifiers in the package. If you
|
||||||
have a few related types whose *implementation* is tightly coupled, placing them
|
have a few related types whose *implementation* is tightly coupled, placing them
|
||||||
in the same package lets you achieve this coupling without polluting the public
|
in the same package lets you achieve this coupling without polluting the public
|
||||||
API with these details.
|
API with these details. A good test for this coupling is to imagine a
|
||||||
|
hypothetical user of two packages, where the packages cover closely related
|
||||||
|
topics: if the user must import both packages in order to use either in any
|
||||||
|
meaningful way, combining them together is usually the right thing to do. The
|
||||||
|
standard library generally demonstrates this kind of scoping and layering well.
|
||||||
|
|
||||||
All of that being said, putting your entire project in a single package would
|
All of that being said, putting your entire project in a single package would
|
||||||
likely make that package too large. When something is conceptually distinct,
|
likely make that package too large. When something is conceptually distinct,
|
||||||
|
@ -776,7 +780,7 @@ var (
|
||||||
ErrMarsupial = errors.New("marsupials are not supported")
|
ErrMarsupial = errors.New("marsupials are not supported")
|
||||||
)
|
)
|
||||||
|
|
||||||
func pet(animal Animal) error {
|
func process(animal Animal) error {
|
||||||
switch {
|
switch {
|
||||||
case seen[animal]:
|
case seen[animal]:
|
||||||
return ErrDuplicate
|
return ErrDuplicate
|
||||||
|
@ -849,6 +853,8 @@ to know if using status codes is the right choice.
|
||||||
|
|
||||||
[`os.PathError`]: https://pkg.go.dev/os#PathError
|
[`os.PathError`]: https://pkg.go.dev/os#PathError
|
||||||
[`errors.Is`]: https://pkg.go.dev/errors#Is
|
[`errors.Is`]: https://pkg.go.dev/errors#Is
|
||||||
|
[`errors.As`]: https://pkg.go.dev/errors#As
|
||||||
|
[`package cmp`]: https://pkg.go.dev/github.com/google/go-cmp/cmp
|
||||||
[status]: https://pkg.go.dev/google.golang.org/grpc/status
|
[status]: https://pkg.go.dev/google.golang.org/grpc/status
|
||||||
[canonical codes]: https://pkg.go.dev/google.golang.org/grpc/codes
|
[canonical codes]: https://pkg.go.dev/google.golang.org/grpc/codes
|
||||||
|
|
||||||
|
@ -978,6 +984,10 @@ func (*FortuneTeller) SuggestFortune(context.Context, *pb.SuggestionRequest) (*p
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
See also:
|
||||||
|
|
||||||
|
* [Error Documentation Conventions](#documentation-conventions-errors)
|
||||||
|
|
||||||
<a id="error-percent-w"></a>
|
<a id="error-percent-w"></a>
|
||||||
|
|
||||||
### Placement of %w in errors
|
### Placement of %w in errors
|
||||||
|
@ -1255,7 +1265,7 @@ information to the reader:
|
||||||
// string.
|
// string.
|
||||||
//
|
//
|
||||||
// format is the format, and data is the interpolation data.
|
// format is the format, and data is the interpolation data.
|
||||||
func Sprintf(format string, data ...interface{}) string
|
func Sprintf(format string, data ...any) string
|
||||||
```
|
```
|
||||||
|
|
||||||
However, this snippet demonstrates a code scenario similar to the previous where
|
However, this snippet demonstrates a code scenario similar to the previous where
|
||||||
|
@ -1272,7 +1282,7 @@ reader:
|
||||||
// the format specification, the function will inline warnings about formatting
|
// the format specification, the function will inline warnings about formatting
|
||||||
// errors into the output string as described by the Format errors section
|
// errors into the output string as described by the Format errors section
|
||||||
// above.
|
// above.
|
||||||
func Sprintf(format string, data ...interface{}) string
|
func Sprintf(format string, data ...any) string
|
||||||
```
|
```
|
||||||
|
|
||||||
Consider your likely audience in choosing what to document and at what depth.
|
Consider your likely audience in choosing what to document and at what depth.
|
||||||
|
@ -1317,9 +1327,9 @@ func (Worker) Run(ctx context.Context) error
|
||||||
```
|
```
|
||||||
|
|
||||||
Where context behavior is different or non-obvious, it should be expressly
|
Where context behavior is different or non-obvious, it should be expressly
|
||||||
documented:
|
documented if any of the following are true.
|
||||||
|
|
||||||
* If the function returns an error other than `ctx.Err()` when the context is
|
* The function returns an error other than `ctx.Err()` when the context is
|
||||||
cancelled:
|
cancelled:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
@ -1330,8 +1340,7 @@ documented:
|
||||||
func (Worker) Run(ctx context.Context) error
|
func (Worker) Run(ctx context.Context) error
|
||||||
```
|
```
|
||||||
|
|
||||||
* If the function has other mechanisms that may interrupt it or affect
|
* The function has other mechanisms that may interrupt it or affect lifetime:
|
||||||
lifetime:
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Good:
|
// Good:
|
||||||
|
@ -1347,7 +1356,7 @@ documented:
|
||||||
func (Worker) Stop()
|
func (Worker) Stop()
|
||||||
```
|
```
|
||||||
|
|
||||||
* If the function has special expectations about context lifetime, lineage, or
|
* The function has special expectations about context lifetime, lineage, or
|
||||||
attached values:
|
attached values:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
@ -1394,9 +1403,9 @@ Similarly, the extra remark about concurrency can safely be removed here:
|
||||||
func (*Buffer) Grow(n int)
|
func (*Buffer) Grow(n int)
|
||||||
```
|
```
|
||||||
|
|
||||||
Documentation is strongly encouraged if:
|
Documentation is strongly encouraged if any of the following are true.
|
||||||
|
|
||||||
* it is unclear whether the operation is read-only or a mutating
|
* It is unclear whether the operation is read-only or mutating:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Good:
|
// Good:
|
||||||
|
@ -1411,7 +1420,7 @@ Documentation is strongly encouraged if:
|
||||||
Why? A cache hit when looking up the key mutate a LRU cache internally. How
|
Why? A cache hit when looking up the key mutate a LRU cache internally. How
|
||||||
this is implemented may not be obvious to all readers.
|
this is implemented may not be obvious to all readers.
|
||||||
|
|
||||||
* synchronization is provided by API
|
* Synchronization is provided by the API:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Good:
|
// Good:
|
||||||
|
@ -1427,7 +1436,7 @@ Documentation is strongly encouraged if:
|
||||||
**Note:** If the API is a type and the API provides synchronization in
|
**Note:** If the API is a type and the API provides synchronization in
|
||||||
entirety, conventionally only the type definition documents the semantics.
|
entirety, conventionally only the type definition documents the semantics.
|
||||||
|
|
||||||
* the API consumes user-implemented types of interfaces, and the interface's
|
* The API consumes user-implemented types of interfaces, and the interface's
|
||||||
consumer has particular concurrency requirements:
|
consumer has particular concurrency requirements:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
@ -1489,6 +1498,84 @@ If it is potentially unclear how to clean up the resources, explain how:
|
||||||
func (c *Client) Get(url string) (resp *Response, err error)
|
func (c *Client) Get(url string) (resp *Response, err error)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
See also:
|
||||||
|
|
||||||
|
* [GoTip #110: Don’t Mix Exit With Defer]
|
||||||
|
|
||||||
|
[GoTip #110: Don’t Mix Exit With Defer]: https://google.github.io/styleguide/go/index.html#gotip
|
||||||
|
|
||||||
|
<a id="documentation-conventions-errors"></a>
|
||||||
|
|
||||||
|
#### Errors
|
||||||
|
|
||||||
|
Document significant error sentinel values or error types that your functions
|
||||||
|
return to callers so that callers can anticipate what types of conditions they
|
||||||
|
can handle in their code.
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Good:
|
||||||
|
package os
|
||||||
|
|
||||||
|
// Read reads up to len(b) bytes from the File and stores them in b. It returns
|
||||||
|
// the number of bytes read and any error encountered.
|
||||||
|
//
|
||||||
|
// At end of file, Read returns 0, io.EOF.
|
||||||
|
func (*File) Read(b []byte) (n int, err error) {
|
||||||
|
```
|
||||||
|
|
||||||
|
When a function returns a specific error type, correctly note whether the error
|
||||||
|
is a pointer receiver or not:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Good:
|
||||||
|
package os
|
||||||
|
|
||||||
|
type PathError struct {
|
||||||
|
Op string
|
||||||
|
Path string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chdir changes the current working directory to the named directory.
|
||||||
|
//
|
||||||
|
// If there is an error, it will be of type *PathError.
|
||||||
|
func Chdir(dir string) error {
|
||||||
|
```
|
||||||
|
|
||||||
|
Documenting whether the values returned are pointer receivers enables callers to
|
||||||
|
correctly compare the errors using [`errors.Is`], [`errors.As`], and
|
||||||
|
[`package cmp`]. This is because a non-pointer value is not equivalent to a
|
||||||
|
pointer value.
|
||||||
|
|
||||||
|
**Note:** In the `Chdir` example, the return type is written as `error` rather
|
||||||
|
than `*PathError` due to
|
||||||
|
[how nil interface values work](https://go.dev/doc/faq#nil_error).
|
||||||
|
|
||||||
|
Document overall error conventions in the
|
||||||
|
[package's documentation](decisions#package-comments) when the behavior is
|
||||||
|
applicable to most errors found in the package:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Good:
|
||||||
|
// Package os provides a platform-independent interface to operating system
|
||||||
|
// functionality.
|
||||||
|
//
|
||||||
|
// Often, more information is available within the error. For example, if a
|
||||||
|
// call that takes a file name fails, such as Open or Stat, the error will
|
||||||
|
// include the failing file name when printed and will be of type *PathError,
|
||||||
|
// which may be unpacked for more information.
|
||||||
|
package os
|
||||||
|
```
|
||||||
|
|
||||||
|
Thoughtful application of these approaches can add
|
||||||
|
[extra information to errors](#error-extra-info) without much effort and help
|
||||||
|
callers avoid adding redundant annotations.
|
||||||
|
|
||||||
|
See also:
|
||||||
|
|
||||||
|
* [Go Tip #106: Error Naming Conventions](https://google.github.io/styleguide/go/index.html#gotip)
|
||||||
|
* [Go Tip #89: When to Use Canonical Status Codes as Errors](https://google.github.io/styleguide/go/index.html#gotip)
|
||||||
|
|
||||||
<a id="documentation-preview"></a>
|
<a id="documentation-preview"></a>
|
||||||
|
|
||||||
### Preview
|
### Preview
|
||||||
|
@ -1944,7 +2031,7 @@ func foo(ctx context.Context) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: [Contexts are never included in option structs](decisions#contexts).
|
**Note:** [Contexts are never included in option structs](decisions#contexts).
|
||||||
|
|
||||||
This option is often preferred when some of the following apply:
|
This option is often preferred when some of the following apply:
|
||||||
|
|
||||||
|
@ -2411,7 +2498,7 @@ func ExerciseGame(t *testing.T, cfg *Config, p chess.Player) error {
|
||||||
if cfg.Simulation == Modem {
|
if cfg.Simulation == Modem {
|
||||||
conn, err := modempool.Allocate()
|
conn, err := modempool.Allocate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("no modem for the opponent could be provisioned: %v", err)
|
t.Fatalf("No modem for the opponent could be provisioned: %v", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() { modempool.Return(conn) })
|
t.Cleanup(func() { modempool.Return(conn) })
|
||||||
}
|
}
|
||||||
|
@ -2437,7 +2524,7 @@ func TestAcceptance(t *testing.T) {
|
||||||
player := deepblue.New()
|
player := deepblue.New()
|
||||||
err := chesstest.ExerciseGame(t, chesstest.SimpleGame, player)
|
err := chesstest.ExerciseGame(t, chesstest.SimpleGame, player)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("deepblue player failed acceptance test: %v", err)
|
t.Errorf("Deep Blue player failed acceptance test: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -2578,14 +2665,14 @@ func paint(color string) error {
|
||||||
func badSetup(t *testing.T) {
|
func badSetup(t *testing.T) {
|
||||||
// This should call t.Helper, but doesn't.
|
// This should call t.Helper, but doesn't.
|
||||||
if err := paint("taupe"); err != nil {
|
if err := paint("taupe"); err != nil {
|
||||||
t.Fatalf("could not paint the house under test: %v", err) // line 15
|
t.Fatalf("Could not paint the house under test: %v", err) // line 15
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mustGoodSetup(t *testing.T) {
|
func mustGoodSetup(t *testing.T) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
if err := paint("lilac"); err != nil {
|
if err := paint("lilac"); err != nil {
|
||||||
t.Fatalf("could not paint the house under test: %v", err)
|
t.Fatalf("Could not paint the house under test: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2605,10 +2692,10 @@ differs:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
=== RUN TestBad
|
=== RUN TestBad
|
||||||
paint_test.go:15: could not paint the house under test: no "taupe" paint today
|
paint_test.go:15: Could not paint the house under test: no "taupe" paint today
|
||||||
--- FAIL: TestBad (0.00s)
|
--- FAIL: TestBad (0.00s)
|
||||||
=== RUN TestGood
|
=== RUN TestGood
|
||||||
paint_test.go:32: could not paint the house under test: no "lilac" paint today
|
paint_test.go:32: Could not paint the house under test: no "lilac" paint today
|
||||||
--- FAIL: TestGood (0.00s)
|
--- FAIL: TestGood (0.00s)
|
||||||
FAIL
|
FAIL
|
||||||
```
|
```
|
||||||
|
@ -2616,7 +2703,7 @@ FAIL
|
||||||
The error with `paint_test.go:15` refers to the line of the setup function that
|
The error with `paint_test.go:15` refers to the line of the setup function that
|
||||||
failed in `badSetup`:
|
failed in `badSetup`:
|
||||||
|
|
||||||
`t.Fatalf("could not paint the house under test: %v", err)`
|
`t.Fatalf("Could not paint the house under test: %v", err)`
|
||||||
|
|
||||||
Whereas `paint_test.go:32` refers to the line of the test that failed in
|
Whereas `paint_test.go:32` refers to the line of the test that failed in
|
||||||
`TestGood`:
|
`TestGood`:
|
||||||
|
@ -2695,33 +2782,41 @@ and those should not depend on the system under test. Therefore, if a test
|
||||||
helper [registers a fatal test failure](#test-helper-error-handling), it can and
|
helper [registers a fatal test failure](#test-helper-error-handling), it can and
|
||||||
should do so from the test's goroutine.
|
should do so from the test's goroutine.
|
||||||
|
|
||||||
|
<a id="t-field-names"></a>
|
||||||
|
|
||||||
|
### Use field names in struct literals
|
||||||
|
|
||||||
<a id="t-field-labels"></a>
|
<a id="t-field-labels"></a>
|
||||||
|
|
||||||
### Use field labels for struct literals
|
In table-driven tests, prefer to specify field names when initializing test case
|
||||||
|
struct literals. This is helpful when the test cases cover a large amount of
|
||||||
In table-driven tests, prefer to specify the key for each test case specified.
|
vertical space (e.g. more than 20-30 lines), when there are adjacent fields with
|
||||||
This is helpful when the test cases cover a large amount of vertical space (e.g.
|
the same type, and also when you wish to omit fields which have the zero value.
|
||||||
more than 20-30 lines), when there are adjacent fields with the same type, and
|
For example:
|
||||||
also when you wish to omit fields which have the zero value. For example:
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Good:
|
// Good:
|
||||||
tests := []struct {
|
func TestStrJoin(t *testing.T) {
|
||||||
foo *pb.Foo
|
tests := []struct {
|
||||||
bar *pb.Bar
|
slice []string
|
||||||
|
separator string
|
||||||
|
skipEmpty bool
|
||||||
want string
|
want string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
foo: pb.Foo_builder{
|
slice: []string{"a", "b", ""},
|
||||||
Name: "foo",
|
separator: ",",
|
||||||
// ...
|
want: "a,b,",
|
||||||
}.Build(),
|
|
||||||
bar: pb.Bar_builder{
|
|
||||||
Name: "bar",
|
|
||||||
// ...
|
|
||||||
}.Build(),
|
|
||||||
want: "result",
|
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
slice: []string{"a", "b", ""},
|
||||||
|
separator: ",",
|
||||||
|
skipEmpty: true,
|
||||||
|
want: "a,b",
|
||||||
|
},
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
// ...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -2742,7 +2837,7 @@ func mustLoadDataset(t *testing.T) []byte {
|
||||||
data, err := os.ReadFile("path/to/your/project/testdata/dataset")
|
data, err := os.ReadFile("path/to/your/project/testdata/dataset")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("could not load dataset: %v", err)
|
t.Fatalf("Could not load dataset: %v", err)
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
@ -2756,7 +2851,7 @@ func TestParseData(t *testing.T) {
|
||||||
data := mustLoadDataset(t)
|
data := mustLoadDataset(t)
|
||||||
parsed, err := ParseData(data)
|
parsed, err := ParseData(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error parsing data: %v", err)
|
t.Fatalf("Unexpected error parsing data: %v", err)
|
||||||
}
|
}
|
||||||
want := &DataTable{ /* ... */ }
|
want := &DataTable{ /* ... */ }
|
||||||
if got := parsed; !cmp.Equal(got, want) {
|
if got := parsed; !cmp.Equal(got, want) {
|
||||||
|
@ -2768,7 +2863,7 @@ func TestListContents(t *testing.T) {
|
||||||
data := mustLoadDataset(t)
|
data := mustLoadDataset(t)
|
||||||
contents, err := ListContents(data)
|
contents, err := ListContents(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error listing contents: %v", err)
|
t.Fatalf("Unexpected error listing contents: %v", err)
|
||||||
}
|
}
|
||||||
want := []string{ /* ... */ }
|
want := []string{ /* ... */ }
|
||||||
if got := contents; !cmp.Equal(got, want) {
|
if got := contents; !cmp.Equal(got, want) {
|
||||||
|
@ -2916,7 +3011,7 @@ func mustLoadDataset(t *testing.T) []byte {
|
||||||
dataset.err = err
|
dataset.err = err
|
||||||
})
|
})
|
||||||
if err := dataset.err; err != nil {
|
if err := dataset.err; err != nil {
|
||||||
t.Fatalf("could not load dataset: %v", err)
|
t.Fatalf("Could not load dataset: %v", err)
|
||||||
}
|
}
|
||||||
return dataset.data
|
return dataset.data
|
||||||
}
|
}
|
||||||
|
@ -2972,8 +3067,8 @@ guidance outlines when each method is preferred.
|
||||||
|
|
||||||
### Prefer "+" for simple cases
|
### Prefer "+" for simple cases
|
||||||
|
|
||||||
Prefer using "+" when concatenating few strings. This method is the
|
Prefer using "+" when concatenating few strings. This method is syntactically
|
||||||
syntactically the simplest and requires no import.
|
the simplest and requires no import.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Good:
|
// Good:
|
||||||
|
@ -3024,7 +3119,7 @@ for i, d := range digitsOfPi {
|
||||||
str := b.String()
|
str := b.String()
|
||||||
```
|
```
|
||||||
|
|
||||||
**NOTE**: For more discussion, see
|
**Note:** For more discussion, see
|
||||||
[GoTip #29: Building Strings Efficiently](https://google.github.io/styleguide/go/index.html#gotip).
|
[GoTip #29: Building Strings Efficiently](https://google.github.io/styleguide/go/index.html#gotip).
|
||||||
|
|
||||||
<a id="string-constants"></a>
|
<a id="string-constants"></a>
|
||||||
|
|
155
go/decisions.md
155
go/decisions.md
|
@ -897,9 +897,14 @@ import (
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
It is acceptable to split the project packages into multiple groups, for example
|
It is acceptable to split the project packages into multiple groups if you want
|
||||||
if you want a separate group for renamed, imported-only-for-side-effects or
|
a separate group, as long as the groups have some meaning. Common reasons to do
|
||||||
another special group of imports.
|
this:
|
||||||
|
|
||||||
|
* renamed imports
|
||||||
|
* packages imported for their side-effects
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Good:
|
// Good:
|
||||||
|
@ -1273,14 +1278,19 @@ maintainable.
|
||||||
|
|
||||||
#### Field names
|
#### Field names
|
||||||
|
|
||||||
Struct literals should usually specify **field names** for types defined outside
|
Struct literals must specify **field names** for types defined outside the
|
||||||
the current package.
|
current package.
|
||||||
|
|
||||||
* Include field names for types from other packages.
|
* Include field names for types from other packages.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Good:
|
// Good:
|
||||||
good := otherpkg.Type{A: 42}
|
// https://pkg.go.dev/encoding/csv#Reader
|
||||||
|
r := csv.Reader{
|
||||||
|
Comma: ',',
|
||||||
|
Comment: '#',
|
||||||
|
FieldsPerRecord: 4,
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The position of fields in a struct and the full set of fields (both of which
|
The position of fields in a struct and the full set of fields (both of which
|
||||||
|
@ -1290,19 +1300,9 @@ the current package.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Bad:
|
// Bad:
|
||||||
// https://pkg.go.dev/encoding/csv#Reader
|
|
||||||
r := csv.Reader{',', '#', 4, false, false, false, false}
|
r := csv.Reader{',', '#', 4, false, false, false, false}
|
||||||
```
|
```
|
||||||
|
|
||||||
Field names may be omitted within small, simple structs whose composition
|
|
||||||
and order are documented as being stable.
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Good:
|
|
||||||
okay := image.Point{42, 54}
|
|
||||||
also := image.Point{X: 42, Y: 54}
|
|
||||||
```
|
|
||||||
|
|
||||||
* For package-local types, field names are optional.
|
* For package-local types, field names are optional.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
@ -1721,33 +1721,6 @@ func (r *SomeType) SomeLongFunctionName(foo1, foo2, foo3 string,
|
||||||
See [best practices](best-practices#funcargs) for a few options for shortening
|
See [best practices](best-practices#funcargs) for a few options for shortening
|
||||||
the call sites of functions that would otherwise have many arguments.
|
the call sites of functions that would otherwise have many arguments.
|
||||||
|
|
||||||
```go
|
|
||||||
// Good:
|
|
||||||
good := foo.Call(long, CallOptions{
|
|
||||||
Names: list,
|
|
||||||
Of: of,
|
|
||||||
The: parameters,
|
|
||||||
Func: all,
|
|
||||||
Args: on,
|
|
||||||
Now: separate,
|
|
||||||
Visible: lines,
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Bad:
|
|
||||||
bad := foo.Call(
|
|
||||||
long,
|
|
||||||
list,
|
|
||||||
of,
|
|
||||||
parameters,
|
|
||||||
all,
|
|
||||||
on,
|
|
||||||
separate,
|
|
||||||
lines,
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
Lines can often be shortened by factoring out local variables.
|
Lines can often be shortened by factoring out local variables.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
@ -1770,9 +1743,9 @@ bad := foo.Call(long, list, of, parameters,
|
||||||
with, arbitrary, line, breaks)
|
with, arbitrary, line, breaks)
|
||||||
```
|
```
|
||||||
|
|
||||||
Do not add comments to specific function parameters. Instead, use an
|
Avoid adding inline comments to specific function arguments where possible.
|
||||||
[option struct](best-practices#option-structure) or add more detail to the
|
Instead, use an [option struct](best-practices#option-structure) or add more
|
||||||
function documentation.
|
detail to the function documentation.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Good:
|
// Good:
|
||||||
|
@ -1787,21 +1760,6 @@ bad := server.New(
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
If call-sites are uncomfortably long, consider refactoring:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Good:
|
|
||||||
// Sometimes variadic arguments can be factored out
|
|
||||||
replacements := []string{
|
|
||||||
"from", "to", // related values can be formatted adjacent to one another
|
|
||||||
"source", "dest",
|
|
||||||
"original", "new",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the replacement struct as inputs to NewReplacer.
|
|
||||||
replacer := strings.NewReplacer(replacements...)
|
|
||||||
```
|
|
||||||
|
|
||||||
If the API cannot be changed or if the local call is unusual (whether or not the
|
If the API cannot be changed or if the local call is unusual (whether or not the
|
||||||
call is too long), it is always permissible to add line breaks if it aids in
|
call is too long), it is always permissible to add line breaks if it aids in
|
||||||
understanding the call.
|
understanding the call.
|
||||||
|
@ -2110,7 +2068,7 @@ exclusively at
|
||||||
func MustParse(version string) *Version {
|
func MustParse(version string) *Version {
|
||||||
v, err := Parse(version)
|
v, err := Parse(version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("MustParse(%q) = _, %v", version, err)
|
panic(fmt.Sprintf("MustParse(%q) = _, %v", version, err))
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
@ -2120,8 +2078,6 @@ func MustParse(version string) *Version {
|
||||||
var DefaultVersion = MustParse("1.2.3")
|
var DefaultVersion = MustParse("1.2.3")
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note:** `log.Fatalf` is not the standard library log. See [#logging].
|
|
||||||
|
|
||||||
The same convention may be used in test helpers that only stop the current test
|
The same convention may be used in test helpers that only stop the current test
|
||||||
(using `t.Fatal`). Such helpers are often convenient in creating test values,
|
(using `t.Fatal`). Such helpers are often convenient in creating test values,
|
||||||
for example in struct fields of [table driven tests](#table-driven-tests), as
|
for example in struct fields of [table driven tests](#table-driven-tests), as
|
||||||
|
@ -2133,7 +2089,7 @@ func mustMarshalAny(t *testing.T, m proto.Message) *anypb.Any {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
any, err := anypb.New(m)
|
any, err := anypb.New(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("MustMarshalAny(t, m) = %v; want %v", err, nil)
|
t.Fatalf("mustMarshalAny(t, m) = %v; want %v", err, nil)
|
||||||
}
|
}
|
||||||
return any
|
return any
|
||||||
}
|
}
|
||||||
|
@ -2189,8 +2145,8 @@ func Version(o *servicepb.Object) (*version.Version, error) {
|
||||||
When you spawn goroutines, make it clear when or whether they exit.
|
When you spawn goroutines, make it clear when or whether they exit.
|
||||||
|
|
||||||
Goroutines can leak by blocking on channel sends or receives. The garbage
|
Goroutines can leak by blocking on channel sends or receives. The garbage
|
||||||
collector will not terminate a goroutine even if the channels it is blocked on
|
collector will not terminate a goroutine blocked on a channel even if no other
|
||||||
are unreachable.
|
goroutine has a reference to the channel.
|
||||||
|
|
||||||
Even when goroutines do not leak, leaving them in-flight when they are no longer
|
Even when goroutines do not leak, leaving them in-flight when they are no longer
|
||||||
needed can cause other subtle and hard-to-diagnose problems. Sending on a
|
needed can cause other subtle and hard-to-diagnose problems. Sending on a
|
||||||
|
@ -2764,11 +2720,11 @@ See also:
|
||||||
|
|
||||||
### Logging
|
### Logging
|
||||||
|
|
||||||
Go programs in the Google codebase use a variant of the
|
Go programs in the Google codebase use a variant of the standard [`log`]
|
||||||
[standard `log` package]. It has a similar but more powerful interface and
|
package. It has a similar but more powerful interface and interoperates well
|
||||||
interoperates well with internal Google systems. An open source version of this
|
with internal Google systems. An open source version of this library is
|
||||||
library is available as [package `glog`], and open source Google projects may
|
available as [package `glog`], and open source Google projects may use that, but
|
||||||
use that, but this guide refers to it as `log` throughout.
|
this guide refers to it as `log` throughout.
|
||||||
|
|
||||||
**Note:** For abnormal program exits, this library uses `log.Fatal` to abort
|
**Note:** For abnormal program exits, this library uses `log.Fatal` to abort
|
||||||
with a stacktrace, and `log.Exit` to stop without one. There is no `log.Panic`
|
with a stacktrace, and `log.Exit` to stop without one. There is no `log.Panic`
|
||||||
|
@ -2785,7 +2741,8 @@ See also:
|
||||||
* When and how to use the log package to
|
* When and how to use the log package to
|
||||||
[stop the program](best-practices#checks-and-panics)
|
[stop the program](best-practices#checks-and-panics)
|
||||||
|
|
||||||
[standard `log` package]: https://pkg.go.dev/log
|
[`log`]: https://pkg.go.dev/log
|
||||||
|
[`log/slog`]: https://pkg.go.dev/log/slog
|
||||||
[package `glog`]: https://pkg.go.dev/github.com/golang/glog
|
[package `glog`]: https://pkg.go.dev/github.com/golang/glog
|
||||||
[`log.Exit`]: https://pkg.go.dev/github.com/golang/glog#Exit
|
[`log.Exit`]: https://pkg.go.dev/github.com/golang/glog#Exit
|
||||||
[`log.Fatal`]: https://pkg.go.dev/github.com/golang/glog#Fatal
|
[`log.Fatal`]: https://pkg.go.dev/github.com/golang/glog#Fatal
|
||||||
|
@ -2978,15 +2935,15 @@ right:
|
||||||
// Bad:
|
// Bad:
|
||||||
package assert
|
package assert
|
||||||
|
|
||||||
func IsNotNil(t *testing.T, name string, val interface{}) {
|
func IsNotNil(t *testing.T, name string, val any) {
|
||||||
if val == nil {
|
if val == nil {
|
||||||
t.Fatalf("data %s = nil, want not nil", name)
|
t.Fatalf("Data %s = nil, want not nil", name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func StringEq(t *testing.T, name, got, want string) {
|
func StringEq(t *testing.T, name, got, want string) {
|
||||||
if got != want {
|
if got != want {
|
||||||
t.Fatalf("data %s = %q, want %q", name, got, want)
|
t.Fatalf("Data %s = %q, want %q", name, got, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -3013,7 +2970,7 @@ want := BlogPost{
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cmp.Equal(got, want) {
|
if !cmp.Equal(got, want) {
|
||||||
t.Errorf("blog post = %v, want = %v", got, want)
|
t.Errorf("Blog post = %v, want = %v", got, want)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -3029,7 +2986,7 @@ func TestBlogPost_VeritableRant(t *testing.T) {
|
||||||
post := BlogPost{Body: "I am Gunnery Sergeant Hartman, your senior drill instructor."}
|
post := BlogPost{Body: "I am Gunnery Sergeant Hartman, your senior drill instructor."}
|
||||||
|
|
||||||
if got, want := postLength(post), 60; got != want {
|
if got, want := postLength(post), 60; got != want {
|
||||||
t.Errorf("length of post = %v, want %v", got, want)
|
t.Errorf("Length of post = %v, want %v", got, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -3361,7 +3318,8 @@ than relying on parsing the error message.
|
||||||
Within unit tests, it is common to only care whether an error occurred or not.
|
Within unit tests, it is common to only care whether an error occurred or not.
|
||||||
If so, then it is sufficient to only test whether the error was non-nil when you
|
If so, then it is sufficient to only test whether the error was non-nil when you
|
||||||
expected an error. If you would like to test that the error semantically matches
|
expected an error. If you would like to test that the error semantically matches
|
||||||
some other error, then consider using `cmp` with [`cmpopts.EquateErrors`].
|
some other error, then consider using [`errors.Is`] or `cmp` with
|
||||||
|
[`cmpopts.EquateErrors`].
|
||||||
|
|
||||||
> **Note:** If a test uses [`cmpopts.EquateErrors`] but all of its `wantErr`
|
> **Note:** If a test uses [`cmpopts.EquateErrors`] but all of its `wantErr`
|
||||||
> values are either `nil` or `cmpopts.AnyError`, then using `cmp` is
|
> values are either `nil` or `cmpopts.AnyError`, then using `cmp` is
|
||||||
|
@ -3370,9 +3328,10 @@ some other error, then consider using `cmp` with [`cmpopts.EquateErrors`].
|
||||||
>
|
>
|
||||||
> ```go
|
> ```go
|
||||||
> // Good:
|
> // Good:
|
||||||
> gotErr := f(test.input) != nil
|
> err := f(test.input)
|
||||||
|
> gotErr := err != nil
|
||||||
> if gotErr != test.wantErr {
|
> if gotErr != test.wantErr {
|
||||||
> t.Errorf("f(%q) returned err = %v, want error presence = %v", test.input, gotErr, test.wantErr)
|
> t.Errorf("f(%q) = %v, want error presence = %v", test.input, err, test.wantErr)
|
||||||
> }
|
> }
|
||||||
> ```
|
> ```
|
||||||
|
|
||||||
|
@ -3381,6 +3340,7 @@ See also
|
||||||
|
|
||||||
[tott-350]: https://testing.googleblog.com/2015/01/testing-on-toilet-change-detector-tests.html
|
[tott-350]: https://testing.googleblog.com/2015/01/testing-on-toilet-change-detector-tests.html
|
||||||
[`cmpopts.EquateErrors`]: https://pkg.go.dev/github.com/google/go-cmp/cmp/cmpopts#EquateErrors
|
[`cmpopts.EquateErrors`]: https://pkg.go.dev/github.com/google/go-cmp/cmp/cmpopts#EquateErrors
|
||||||
|
[`errors.Is`]: https://pkg.go.dev/errors#Is
|
||||||
|
|
||||||
<a id="test-structure"></a>
|
<a id="test-structure"></a>
|
||||||
|
|
||||||
|
@ -3471,6 +3431,9 @@ t.Run("check that there is no mention of scratched records or hovercrafts", ...)
|
||||||
t.Run("AM/PM confusion", ...)
|
t.Run("AM/PM confusion", ...)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
See also
|
||||||
|
[Go Tip #117: Subtest Names](https://google.github.io/styleguide/go/index.html#gotip).
|
||||||
|
|
||||||
[Go test runner]: https://golang.org/cmd/go/#hdr-Testing_flags
|
[Go test runner]: https://golang.org/cmd/go/#hdr-Testing_flags
|
||||||
[identify the inputs]: #identify-the-input
|
[identify the inputs]: #identify-the-input
|
||||||
[special meaning for test filters]: https://blog.golang.org/subtests#:~:text=Perhaps%20a%20bit,match%20any%20tests
|
[special meaning for test filters]: https://blog.golang.org/subtests#:~:text=Perhaps%20a%20bit,match%20any%20tests
|
||||||
|
@ -3491,18 +3454,17 @@ similar testing logic.
|
||||||
[tests of `fmt.Sprintf`]: https://cs.opensource.google/go/go/+/master:src/fmt/fmt_test.go
|
[tests of `fmt.Sprintf`]: https://cs.opensource.google/go/go/+/master:src/fmt/fmt_test.go
|
||||||
[tests for `net.Dial`]: https://cs.opensource.google/go/go/+/master:src/net/dial_test.go;l=318;drc=5b606a9d2b7649532fe25794fa6b99bd24e7697c
|
[tests for `net.Dial`]: https://cs.opensource.google/go/go/+/master:src/net/dial_test.go;l=318;drc=5b606a9d2b7649532fe25794fa6b99bd24e7697c
|
||||||
|
|
||||||
Here is the minimal structure of a table-driven test, copied from the standard
|
Here is the minimal structure of a table-driven test. If needed, you may use
|
||||||
`strings` library. If needed, you may use different names, move the test slice
|
different names or add extra facilities such as subtests or setup and cleanup
|
||||||
into the test function, or add extra facilities such as subtests or setup and
|
functions. Always keep [useful test failures](#useful-test-failures) in mind.
|
||||||
cleanup functions. Always keep [useful test failures](#useful-test-failures) in
|
|
||||||
mind.
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Good:
|
// Good:
|
||||||
var compareTests = []struct {
|
func TestCompare(t *testing.T) {
|
||||||
|
compareTests := []struct {
|
||||||
a, b string
|
a, b string
|
||||||
i int
|
want int
|
||||||
}{
|
}{
|
||||||
{"", "", 0},
|
{"", "", 0},
|
||||||
{"a", "", 1},
|
{"a", "", 1},
|
||||||
{"", "a", -1},
|
{"", "a", -1},
|
||||||
|
@ -3517,13 +3479,12 @@ var compareTests = []struct {
|
||||||
{"abcdefgh", "abcdefgh", 0},
|
{"abcdefgh", "abcdefgh", 0},
|
||||||
{"abcdefghi", "abcdefghi", 0},
|
{"abcdefghi", "abcdefghi", 0},
|
||||||
{"abcdefghi", "abcdefghj", -1},
|
{"abcdefghi", "abcdefghj", -1},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCompare(t *testing.T) {
|
for _, test := range compareTests {
|
||||||
for _, tt := range compareTests {
|
got := Compare(test.a, test.b)
|
||||||
cmp := Compare(tt.a, tt.b)
|
if got != test.want {
|
||||||
if cmp != tt.i {
|
t.Errorf("Compare(%q, %q) = %v, want %v", test.a, test.b, got, test.want)
|
||||||
t.Errorf(`Compare(%q, %q) = %v`, tt.a, tt.b, cmp)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3639,7 +3600,7 @@ func TestDecode(t *testing.T) {
|
||||||
case prod:
|
case prod:
|
||||||
codex = setupCodex(t)
|
codex = setupCodex(t)
|
||||||
default:
|
default:
|
||||||
t.Fatalf("unknown codex type: %v", codex)
|
t.Fatalf("Unknown codex type: %v", codex)
|
||||||
}
|
}
|
||||||
output, err := Decode(test.input, codex)
|
output, err := Decode(test.input, codex)
|
||||||
if got, want := output, test.output; got != want {
|
if got, want := output, test.output; got != want {
|
||||||
|
@ -3673,7 +3634,7 @@ tests := []struct {
|
||||||
}
|
}
|
||||||
for i, d := range tests {
|
for i, d := range tests {
|
||||||
if strings.ToUpper(d.input) != d.want {
|
if strings.ToUpper(d.input) != d.want {
|
||||||
t.Errorf("failed on case #%d", i)
|
t.Errorf("Failed on case #%d", i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -419,8 +419,8 @@ initial capitalization.
|
||||||
|
|
||||||
### Line length
|
### Line length
|
||||||
|
|
||||||
There is no fixed line length for Go source code. If a line feels too long, it
|
There is no fixed line length for Go source code. If a line feels too long,
|
||||||
should be refactored instead of broken. If it is already as short as it is
|
prefer refactoring instead of splitting it. If it is already as short as it is
|
||||||
practical for it to be, the line should be allowed to remain long.
|
practical for it to be, the line should be allowed to remain long.
|
||||||
|
|
||||||
Do not split a line:
|
Do not split a line:
|
||||||
|
|
338
javaguide.css
338
javaguide.css
|
@ -2,13 +2,16 @@ table {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
|
|
||||||
td, th {
|
td,
|
||||||
|
th {
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
padding: 2px 12px;
|
padding: 2px 12px;
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
code, samp, var {
|
code,
|
||||||
|
samp,
|
||||||
|
var {
|
||||||
color: #060;
|
color: #060;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,16 +20,9 @@ pre {
|
||||||
display: block;
|
display: block;
|
||||||
color: #060;
|
color: #060;
|
||||||
background-color: #e8fff6;
|
background-color: #e8fff6;
|
||||||
border-color: #f0fff0;
|
border: 1px solid #f0fff0;
|
||||||
border-style: solid;
|
|
||||||
border-top-width: 1px;
|
|
||||||
border-bottom-width: 1px;
|
|
||||||
border-right-width: 1px;
|
|
||||||
border-left-width: 5px;
|
border-left-width: 5px;
|
||||||
padding-left: 12px;
|
padding: 4px 12px;
|
||||||
padding-right: 12px;
|
|
||||||
padding-top: 4px;
|
|
||||||
padding-bottom: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pre.badcode {
|
pre.badcode {
|
||||||
|
@ -42,10 +38,8 @@ hr {
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
margin-top:2em;
|
margin: 2em 10% 0;
|
||||||
margin-left:10%;
|
padding: 0;
|
||||||
margin-right:10%;
|
|
||||||
padding:0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.bp-reset-element,
|
.bp-reset-element,
|
||||||
|
@ -104,32 +98,32 @@ tbody,
|
||||||
tfoot,
|
tfoot,
|
||||||
thead,
|
thead,
|
||||||
tr {
|
tr {
|
||||||
margin:0;
|
margin: 0;
|
||||||
padding:0;
|
padding: 0;
|
||||||
border:0;
|
border: 0;
|
||||||
font-weight:inherit;
|
font-weight: inherit;
|
||||||
font-style:inherit;
|
font-style: inherit;
|
||||||
font-size:100%;
|
font-size: 100%;
|
||||||
font-family:inherit;
|
font-family: inherit;
|
||||||
vertical-align:baseline;
|
vertical-align: baseline;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family:'Arial', sans-serif;
|
font-family: 'Arial', sans-serif;
|
||||||
font-size:81.25%;
|
font-size: 81.25%;
|
||||||
color:#222;
|
color: #222;
|
||||||
background-color:#fff;
|
background-color: #fff;
|
||||||
line-height:1.67;
|
line-height: 1.67;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.change {
|
.change {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
margin-bottom:1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
em {
|
em {
|
||||||
font-style: italic
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
|
@ -138,12 +132,12 @@ h3,
|
||||||
h4,
|
h4,
|
||||||
h5,
|
h5,
|
||||||
h6 {
|
h6 {
|
||||||
font-weight:bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
margin-bottom:.50em;
|
margin-bottom: 0.5em;
|
||||||
text-align: center
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2,
|
h2,
|
||||||
|
@ -151,22 +145,36 @@ h3,
|
||||||
h4,
|
h4,
|
||||||
h5,
|
h5,
|
||||||
h6 {
|
h6 {
|
||||||
margin-top:1.5em;
|
margin-top: 1.5em;
|
||||||
margin-bottom:.75em;
|
margin-bottom: 0.75em;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {font-size:200%;}
|
h1 {
|
||||||
h2 {font-size:167%;}
|
font-size: 200%;
|
||||||
h3 {font-size:133%;}
|
}
|
||||||
h4 {font-size:120%;}
|
|
||||||
h5 {font-size:110%;}
|
h2 {
|
||||||
|
font-size: 167%;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 133%;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 120%;
|
||||||
|
}
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
font-size: 110%;
|
||||||
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin:0 0 1.5em;
|
margin: 0 0 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
a[href=''] {
|
a[href=''] {
|
||||||
cursor:default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 img,
|
h1 img,
|
||||||
|
@ -175,238 +183,238 @@ h3 img,
|
||||||
h4 img,
|
h4 img,
|
||||||
h5 img,
|
h5 img,
|
||||||
h6 img {
|
h6 img {
|
||||||
margin:0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
a img {
|
a img {
|
||||||
border:none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
margin:1.5em 0;
|
margin: 1.5em 0;
|
||||||
white-space:pre;
|
white-space: pre;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre,
|
pre,
|
||||||
code,
|
code,
|
||||||
kbd,
|
kbd,
|
||||||
tt {
|
tt {
|
||||||
font:1em 'Droid Sans Mono', monospace;
|
font: 1em 'Droid Sans Mono', monospace;
|
||||||
line-height:1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
dl {
|
dl {
|
||||||
margin:0 0 1.5em 0;
|
margin: 0 0 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
dl dt {
|
dl dt {
|
||||||
font-weight:bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
dd {
|
dd {
|
||||||
margin-left:1.5em;
|
margin-left: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
dd.toc3 {
|
dd.toc3 {
|
||||||
margin-left:3em;
|
margin-left: 3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr {
|
hr {
|
||||||
height:0;
|
height: 0;
|
||||||
border:0;
|
border: 0;
|
||||||
border-top:1px solid #ccc;
|
border-top: 1px solid #ccc;
|
||||||
background-color:#ccc;
|
background-color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
border:1px solid #bbb;
|
border: 1px solid #bbb;
|
||||||
border-spacing:0;
|
border-spacing: 0;
|
||||||
border-collapse:collapse;
|
border-collapse: collapse;
|
||||||
margin:0 0 1.5em;
|
margin: 0 0 1.5em;
|
||||||
vertical-align:middle;
|
vertical-align: middle;
|
||||||
width:100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.unlined,
|
table.unlined,
|
||||||
table.unlined th,
|
table.unlined th,
|
||||||
table.unlined tr,
|
table.unlined tr,
|
||||||
table.unlined td {
|
table.unlined td {
|
||||||
border:0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
th,
|
th,
|
||||||
td,
|
td,
|
||||||
caption {
|
caption {
|
||||||
float:none !important;
|
float: none !important;
|
||||||
text-align:left;
|
text-align: left;
|
||||||
font-weight:normal;
|
font-weight: normal;
|
||||||
vertical-align:middle;
|
vertical-align: middle;
|
||||||
padding:4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
caption {
|
caption {
|
||||||
padding:0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
td {
|
td {
|
||||||
border:1px solid #bbb;
|
border: 1px solid #bbb;
|
||||||
vertical-align:top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
th {
|
th {
|
||||||
border:0;
|
border: 0;
|
||||||
border-bottom:1px solid black;
|
border-bottom: 1px solid black;
|
||||||
font-weight:bold;
|
font-weight: bold;
|
||||||
background:rgb(229, 236, 249);
|
background: rgb(229, 236, 249);
|
||||||
}
|
}
|
||||||
|
|
||||||
table th code {
|
table th code {
|
||||||
background-color:inherit;
|
background-color: inherit;
|
||||||
color:inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
table tfoot th {
|
table tfoot th {
|
||||||
border:1px solid #bbb;
|
border: 1px solid #bbb;
|
||||||
}
|
}
|
||||||
|
|
||||||
tfoot {
|
tfoot {
|
||||||
font-style:italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
caption {
|
caption {
|
||||||
background:#eee;
|
background: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
table[border='0'] {
|
table[border='0'] {
|
||||||
border:none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
table[border='0']>tbody>tr>td,
|
table[border='0'] > tbody > tr > td,
|
||||||
table[border='0']>tr>td {
|
table[border='0'] > tr > td {
|
||||||
border:none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.alt td,
|
tr.alt td,
|
||||||
td.alt {
|
td.alt {
|
||||||
background-color:#efefef;
|
background-color: #efefef;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.striped tr:nth-child(even) td,
|
table.striped tr:nth-child(even) td,
|
||||||
table tr.even td {
|
table tr.even td {
|
||||||
background:#efefef;
|
background: #efefef;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.columns {
|
table.columns {
|
||||||
border:none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.columns>tbody>tr>td,
|
table.columns > tbody > tr > td,
|
||||||
table.columns>tr>td {
|
table.columns > tr > td {
|
||||||
border:none;
|
border: none;
|
||||||
padding:0 3em 0 0;
|
padding: 0 3em 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.columns>tbody>tr>td:last-child,
|
table.columns > tbody > tr > td:last-child,
|
||||||
table.columns>tr>td:last-child {
|
table.columns > tr > td:last-child {
|
||||||
border:none;
|
border: none;
|
||||||
padding:0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul,
|
ul,
|
||||||
ol {
|
ol {
|
||||||
margin:0 1.5em 1.5em 0;
|
margin: 0 1.5em 1.5em 0;
|
||||||
padding-left:2em;
|
padding-left: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
li ul,
|
li ul,
|
||||||
li ol {
|
li ol {
|
||||||
margin:0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
list-style-type:disc;
|
list-style-type: disc;
|
||||||
}
|
}
|
||||||
|
|
||||||
ol {
|
ol {
|
||||||
list-style-type:decimal;
|
list-style-type: decimal;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
list-style-type:disc;
|
list-style-type: disc;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul ul {
|
ul ul {
|
||||||
list-style-type:circle;
|
list-style-type: circle;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul ul ul {
|
ul ul ul {
|
||||||
list-style-type:square;
|
list-style-type: square;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.disc {
|
ul.disc {
|
||||||
list-style-type:disc;
|
list-style-type: disc;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.circle {
|
ul.circle {
|
||||||
list-style-type:circle;
|
list-style-type: circle;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.square {
|
ul.square {
|
||||||
list-style-type:square;
|
list-style-type: square;
|
||||||
}
|
}
|
||||||
|
|
||||||
ol {
|
ol {
|
||||||
list-style-type:decimal;
|
list-style-type: decimal;
|
||||||
}
|
}
|
||||||
|
|
||||||
ol ol {
|
ol ol {
|
||||||
list-style-type:lower-alpha;
|
list-style-type: lower-alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
ol ol ol {
|
ol ol ol {
|
||||||
list-style-type:lower-roman;
|
list-style-type: lower-roman;
|
||||||
}
|
}
|
||||||
|
|
||||||
ol ul {
|
ol ul {
|
||||||
list-style-type:circle;
|
list-style-type: circle;
|
||||||
}
|
}
|
||||||
|
|
||||||
ol.decimal {
|
ol.decimal {
|
||||||
list-style-type:decimal;
|
list-style-type: decimal;
|
||||||
}
|
}
|
||||||
|
|
||||||
ol.upper-alpha {
|
ol.upper-alpha {
|
||||||
list-style-type:upper-alpha;
|
list-style-type: upper-alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
ol.lower-alpha {
|
ol.lower-alpha {
|
||||||
list-style-type:lower-alpha;
|
list-style-type: lower-alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
ol.upper-roman {
|
ol.upper-roman {
|
||||||
list-style-type:upper-roman;
|
list-style-type: upper-roman;
|
||||||
}
|
}
|
||||||
|
|
||||||
ol.lower-roman {
|
ol.lower-roman {
|
||||||
list-style-type:lower-roman;
|
list-style-type: lower-roman;
|
||||||
}
|
}
|
||||||
|
|
||||||
ol.nolist,
|
ol.nolist,
|
||||||
ul.nolist {
|
ul.nolist {
|
||||||
padding-left:0;
|
padding-left: 0;
|
||||||
list-style-image:none;
|
list-style-image: none;
|
||||||
list-style-type:none;
|
list-style-type: none;
|
||||||
margin-left:0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.center {
|
.center {
|
||||||
text-align:center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
code,
|
code,
|
||||||
kbd,
|
kbd,
|
||||||
pre {
|
pre {
|
||||||
color:#009900;
|
color: #090;
|
||||||
}
|
}
|
||||||
|
|
||||||
kbd {
|
kbd {
|
||||||
|
@ -414,107 +422,108 @@ kbd {
|
||||||
}
|
}
|
||||||
|
|
||||||
table.striped code {
|
table.striped code {
|
||||||
background-color:inherit;
|
background-color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
padding:6px 10px;
|
padding: 6px 10px;
|
||||||
background-color:#FAFAFA;
|
background-color: #fafafa;
|
||||||
border:1px solid #bbb;
|
border: 1px solid #bbb;
|
||||||
overflow:auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre.prettyprint {
|
pre.prettyprint {
|
||||||
padding:6px 10px !important;
|
padding: 6px 10px !important;
|
||||||
border:1px solid #bbb !important;
|
border: 1px solid #bbb !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
code.bad, code.badcode {
|
code.bad,
|
||||||
|
code.badcode {
|
||||||
color: magenta;
|
color: magenta;
|
||||||
}
|
}
|
||||||
pre.bad, pre.badcode {
|
|
||||||
background-color:#ffe6d8;
|
pre.bad,
|
||||||
border-top:1px inset #a03;
|
pre.badcode {
|
||||||
border-left:1px inset #a03;
|
background-color: #ffe6d8;
|
||||||
|
border-top: 1px inset #a03;
|
||||||
|
border-left: 1px inset #a03;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tip {
|
.tip {
|
||||||
background-color:#fffbd9;
|
background-color: #fffbd9;
|
||||||
padding:6px 8px 6px 10px;
|
padding: 6px 8px 6px 10px;
|
||||||
border-left:6px solid #ffef70;
|
border-left: 6px solid #ffef70;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note {
|
.note {
|
||||||
background-color:#e5ecf9;
|
background-color: #e5ecf9;
|
||||||
padding:6px 8px 6px 10px;
|
padding: 6px 8px 6px 10px;
|
||||||
border-left:6px solid #36c;
|
border-left: 6px solid #36c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
|
|
||||||
.str {
|
.str {
|
||||||
color:#060;
|
color: #060;
|
||||||
}
|
}
|
||||||
|
|
||||||
.kwd {
|
.kwd {
|
||||||
color:#006;
|
color: #006;
|
||||||
font-weight:bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.com {
|
.com {
|
||||||
color:#600;
|
color: #600;
|
||||||
font-style:italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
.typ {
|
.typ {
|
||||||
color:#404;
|
color: #404;
|
||||||
font-weight:bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lit {
|
.lit {
|
||||||
color:#044;
|
color: #044;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pun,
|
.pun,
|
||||||
.opn,
|
.opn,
|
||||||
.clo {
|
.clo {
|
||||||
color:#440;
|
color: #440;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pln {
|
.pln {
|
||||||
color:#000;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tag {
|
.tag {
|
||||||
color:#006;
|
color: #006;
|
||||||
font-weight:bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.atn {
|
.atn {
|
||||||
color:#404;
|
color: #404;
|
||||||
}
|
}
|
||||||
|
|
||||||
.atv {
|
.atv {
|
||||||
color:#060;
|
color: #060;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-style:italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ol.linenums {
|
ol.linenums {
|
||||||
margin-top:0;
|
margin-top: 0;
|
||||||
margin-bottom:0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
background-color:#FAFAFA;
|
background-color: #fafafa;
|
||||||
padding: 0.25em 0.5em;
|
padding: 0.25em 0.5em;
|
||||||
white-space: nowrap
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* TOC CSS */
|
/* TOC CSS */
|
||||||
|
|
||||||
table.columns {
|
table.columns {
|
||||||
|
@ -552,15 +561,16 @@ li.toc_entry {
|
||||||
* at href boundaries
|
* at href boundaries
|
||||||
*/
|
*/
|
||||||
li.toc_entry::after {
|
li.toc_entry::after {
|
||||||
content: " ";
|
content: ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
li.toc_entry a {
|
li.toc_entry a {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Horizontal TOC */
|
/* Horizontal TOC */
|
||||||
.toc td, .toc th {
|
.toc td,
|
||||||
|
.toc th {
|
||||||
border-width: 1px 5px;
|
border-width: 1px 5px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
@ -568,7 +578,7 @@ li.toc_entry a {
|
||||||
/* Vertical TOC */
|
/* Vertical TOC */
|
||||||
|
|
||||||
.toc td.two_columns {
|
.toc td.two_columns {
|
||||||
border-width: 0px;
|
border-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Numbered sections */
|
/* Numbered sections */
|
||||||
|
|
353
pyguide.md
353
pyguide.md
|
@ -47,6 +47,7 @@ See README.md for details.
|
||||||
+ [3.8.2 Modules](#s3.8.2-comments-in-modules)
|
+ [3.8.2 Modules](#s3.8.2-comments-in-modules)
|
||||||
+ [3.8.2.1 Test modules](#s3.8.2.1-test-modules)
|
+ [3.8.2.1 Test modules](#s3.8.2.1-test-modules)
|
||||||
+ [3.8.3 Functions and Methods](#s3.8.3-functions-and-methods)
|
+ [3.8.3 Functions and Methods](#s3.8.3-functions-and-methods)
|
||||||
|
+ [3.8.3.1 Overridden Methods](#s3.8.3.1-overridden-methods)
|
||||||
+ [3.8.4 Classes](#s3.8.4-comments-in-classes)
|
+ [3.8.4 Classes](#s3.8.4-comments-in-classes)
|
||||||
+ [3.8.5 Block and Inline Comments](#s3.8.5-block-and-inline-comments)
|
+ [3.8.5 Block and Inline Comments](#s3.8.5-block-and-inline-comments)
|
||||||
+ [3.8.6 Punctuation, Spelling, and Grammar](#s3.8.6-punctuation-spelling-and-grammar)
|
+ [3.8.6 Punctuation, Spelling, and Grammar](#s3.8.6-punctuation-spelling-and-grammar)
|
||||||
|
@ -213,8 +214,8 @@ that the arguments are actually unused.
|
||||||
<a id="imports"></a>
|
<a id="imports"></a>
|
||||||
### 2.2 Imports
|
### 2.2 Imports
|
||||||
|
|
||||||
Use `import` statements for packages and modules only, not for individual
|
Use `import` statements for packages and modules only, not for individual types,
|
||||||
classes or functions.
|
classes, or functions.
|
||||||
|
|
||||||
<a id="s2.2.1-definition"></a>
|
<a id="s2.2.1-definition"></a>
|
||||||
<a id="221-definition"></a>
|
<a id="221-definition"></a>
|
||||||
|
@ -404,11 +405,15 @@ Exceptions must follow certain conditions:
|
||||||
|
|
||||||
- Make use of built-in exception classes when it makes sense. For example,
|
- Make use of built-in exception classes when it makes sense. For example,
|
||||||
raise a `ValueError` to indicate a programming mistake like a violated
|
raise a `ValueError` to indicate a programming mistake like a violated
|
||||||
precondition (such as if you were passed a negative number but required a
|
precondition, such as may happen when validating function arguments.
|
||||||
positive one). Do not use `assert` statements for validating argument values
|
|
||||||
of a public API. `assert` is used to ensure internal correctness, not to
|
- Do not use `assert` statements in place of conditionals or validating
|
||||||
enforce correct usage nor to indicate that some unexpected event occurred.
|
preconditions. They must not be critical to the application logic. A litmus
|
||||||
If an exception is desired in the latter cases, use a raise statement. For
|
test would be that the `assert` could be removed without breaking the code.
|
||||||
|
`assert` conditionals are
|
||||||
|
[not guaranteed](https://docs.python.org/3/reference/simple_stmts.html#the-assert-statement)
|
||||||
|
to be evaluated. For [pytest](https://pytest.org) based tests, `assert` is
|
||||||
|
okay and expected to verify expectations. For
|
||||||
example:
|
example:
|
||||||
|
|
||||||
|
|
||||||
|
@ -435,6 +440,7 @@ Exceptions must follow certain conditions:
|
||||||
if port is None:
|
if port is None:
|
||||||
raise ConnectionError(
|
raise ConnectionError(
|
||||||
f'Could not connect to service on port {minimum} or higher.')
|
f'Could not connect to service on port {minimum} or higher.')
|
||||||
|
# The code does not depend on the result of this assert.
|
||||||
assert port >= minimum, (
|
assert port >= minimum, (
|
||||||
f'Unexpected port {port} when minimum was {minimum}.')
|
f'Unexpected port {port} when minimum was {minimum}.')
|
||||||
return port
|
return port
|
||||||
|
@ -452,8 +458,10 @@ Exceptions must follow certain conditions:
|
||||||
The new minimum port.
|
The new minimum port.
|
||||||
"""
|
"""
|
||||||
assert minimum >= 1024, 'Minimum port must be at least 1024.'
|
assert minimum >= 1024, 'Minimum port must be at least 1024.'
|
||||||
|
# The following code depends on the previous assert.
|
||||||
port = self._find_next_open_port(minimum)
|
port = self._find_next_open_port(minimum)
|
||||||
assert port is not None
|
assert port is not None
|
||||||
|
# The type checking of the return statement relies on the assert.
|
||||||
return port
|
return port
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -642,20 +650,18 @@ Complicated comprehensions or generator expressions can be hard to read.
|
||||||
<a id="comprehensions-decision"></a>
|
<a id="comprehensions-decision"></a>
|
||||||
#### 2.7.4 Decision
|
#### 2.7.4 Decision
|
||||||
|
|
||||||
Okay to use for simple cases. Each portion must fit on one line: mapping
|
Comprehensions are allowed, however multiple `for` clauses or filter expressions
|
||||||
expression, `for` clause, filter expression. Multiple `for` clauses or filter
|
are not permitted. Optimize for readability, not conciseness.
|
||||||
expressions are not permitted. Use loops instead when things get more
|
|
||||||
complicated.
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
Yes:
|
Yes:
|
||||||
result = [mapping_expr for value in iterable if filter_expr]
|
result = [mapping_expr for value in iterable if filter_expr]
|
||||||
|
|
||||||
result = [{'key': value} for value in iterable
|
result = [
|
||||||
if a_long_filter_expression(value)]
|
is_valid(metric={'key': value})
|
||||||
|
for value in interesting_iterable
|
||||||
result = [complicated_transform(x)
|
if a_longer_filter_expression(value)
|
||||||
for x in iterable if predicate(x)]
|
]
|
||||||
|
|
||||||
descriptive_name = [
|
descriptive_name = [
|
||||||
transform({'key': key, 'value': value}, color='black')
|
transform({'key': key, 'value': value}, color='black')
|
||||||
|
@ -669,32 +675,29 @@ Yes:
|
||||||
if x * y > 10:
|
if x * y > 10:
|
||||||
result.append((x, y))
|
result.append((x, y))
|
||||||
|
|
||||||
return {x: complicated_transform(x)
|
return {
|
||||||
|
x: complicated_transform(x)
|
||||||
for x in long_generator_function(parameter)
|
for x in long_generator_function(parameter)
|
||||||
if x is not None}
|
if x is not None
|
||||||
|
}
|
||||||
|
|
||||||
squares_generator = (x**2 for x in range(10))
|
return (x**2 for x in range(10))
|
||||||
|
|
||||||
unique_names = {user.name for user in users if user is not None}
|
unique_names = {user.name for user in users if user is not None}
|
||||||
|
|
||||||
eat(jelly_bean for jelly_bean in jelly_beans
|
|
||||||
if jelly_bean.color == 'black')
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```python
|
```python
|
||||||
No:
|
No:
|
||||||
result = [complicated_transform(
|
|
||||||
x, some_argument=x+1)
|
|
||||||
for x in iterable if predicate(x)]
|
|
||||||
|
|
||||||
result = [(x, y) for x in range(10) for y in range(5) if x * y > 10]
|
result = [(x, y) for x in range(10) for y in range(5) if x * y > 10]
|
||||||
|
|
||||||
return ((x, y, z)
|
return (
|
||||||
|
(x, y, z)
|
||||||
for x in range(5)
|
for x in range(5)
|
||||||
for y in range(5)
|
for y in range(5)
|
||||||
if x != y
|
if x != y
|
||||||
for z in range(5)
|
for z in range(5)
|
||||||
if y != z)
|
if y != z
|
||||||
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
<a id="s2.8-default-iterators-and-operators"></a>
|
<a id="s2.8-default-iterators-and-operators"></a>
|
||||||
|
@ -848,8 +851,8 @@ function may only contain an expression.
|
||||||
<a id="lambdas-decision"></a>
|
<a id="lambdas-decision"></a>
|
||||||
#### 2.10.4 Decision
|
#### 2.10.4 Decision
|
||||||
|
|
||||||
Okay to use them for one-liners. If the code inside the lambda function is
|
Lambdas are allowed. If the code inside the lambda function spans multiple lines
|
||||||
longer than 60-80 chars, it's probably better to define it as a regular
|
or is longer than 60-80 chars, it might be better to define it as a regular
|
||||||
[nested function](#lexical-scoping).
|
[nested function](#lexical-scoping).
|
||||||
|
|
||||||
For common operations like multiplication, use the functions from the `operator`
|
For common operations like multiplication, use the functions from the `operator`
|
||||||
|
@ -992,7 +995,7 @@ _FOO = flags.DEFINE_string(...)
|
||||||
|
|
||||||
No: def foo(a, b=[]):
|
No: def foo(a, b=[]):
|
||||||
...
|
...
|
||||||
No: def foo(a, b=time.time()): # The time the module was loaded???
|
No: def foo(a, b=time.time()): # Is `b` supposed to represent when this module was loaded?
|
||||||
...
|
...
|
||||||
No: def foo(a, b=_FOO.value): # sys.argv has not yet been parsed...
|
No: def foo(a, b=_FOO.value): # sys.argv has not yet been parsed...
|
||||||
...
|
...
|
||||||
|
@ -1071,7 +1074,7 @@ implement computations a subclass may ever want to override and extend.
|
||||||
<a id="truefalse-evaluations"></a>
|
<a id="truefalse-evaluations"></a>
|
||||||
### 2.14 True/False Evaluations
|
### 2.14 True/False Evaluations
|
||||||
|
|
||||||
Use the "implicit" false if at all possible.
|
Use the "implicit" false if at all possible (with a few caveats).
|
||||||
|
|
||||||
<a id="s2.14.1-definition"></a>
|
<a id="s2.14.1-definition"></a>
|
||||||
<a id="2141-definition"></a>
|
<a id="2141-definition"></a>
|
||||||
|
@ -1798,6 +1801,150 @@ Trailing commas in sequences of items are recommended only when the closing
|
||||||
container token `]`, `)`, or `}` does not appear on the same line as the final
|
container token `]`, `)`, or `}` does not appear on the same line as the final
|
||||||
element, as well as for tuples with a single element. The presence of a trailing
|
element, as well as for tuples with a single element. The presence of a trailing
|
||||||
comma is also used as a hint to our Python code auto-formatter
|
comma is also used as a hint to our Python code auto-formatter
|
||||||
|
[Black](https://github.com/psf/black) or [Pyink](https://github.com/google/pyink)
|
||||||
|
to direct it to auto-format the container of items to one item per line when the
|
||||||
|
`,` after the final element is present.
|
||||||
|
|
||||||
|
```python
|
||||||
|
Yes: golomb3 = [0, 1, 3]
|
||||||
|
golomb4 = [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
4,
|
||||||
|
6,
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
No: golomb4 = [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
4,
|
||||||
|
6,]
|
||||||
|
```
|
||||||
|
|
||||||
|
<a id="s3.5-blank-lines"></a>
|
||||||
|
<a id="35-blank-lines"></a>
|
||||||
|
|
||||||
|
<a id="blank-lines"></a>
|
||||||
|
### 3.5 Blank Lines
|
||||||
|
|
||||||
|
Two blank lines between top-level definitions, be they function or class
|
||||||
|
definitions. One blank line between method definitions and between the docstring
|
||||||
|
of a `class` and the first method. No blank line following a `def` line. Use
|
||||||
|
single blank lines as you judge appropriate within functions or methods.
|
||||||
|
|
||||||
|
Blank lines need not be anchored to the definition. For example, related
|
||||||
|
comments immediately preceding function, class, and method definitions can make
|
||||||
|
sense. Consider if your comment might be more useful as part of the docstring.
|
||||||
|
|
||||||
|
<a id="s3.6-whitespace"></a>
|
||||||
|
<a id="36-whitespace"></a>
|
||||||
|
|
||||||
|
<a id="whitespace"></a>
|
||||||
|
### 3.6 Whitespace
|
||||||
|
|
||||||
|
Follow standard typographic rules for the use of spaces around punctuation.
|
||||||
|
|
||||||
|
No whitespace inside parentheses, brackets or braces.
|
||||||
|
|
||||||
|
```python
|
||||||
|
Yes: spam(ham[1], {'eggs': 2}, [])
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
No: spam( ham[ 1 ], { 'eggs': 2 }, [ ] )
|
||||||
|
```
|
||||||
|
|
||||||
|
No whitespace before a comma, semicolon, or colon. Do use whitespace after a
|
||||||
|
comma, semicolon, or colon, except at the end of the line.
|
||||||
|
|
||||||
|
```python
|
||||||
|
Yes: if x == 4:
|
||||||
|
print(x, y)
|
||||||
|
x, y = y, x
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
No: if x == 4 :
|
||||||
|
print(x , y)
|
||||||
|
x , y = y , x
|
||||||
|
```
|
||||||
|
|
||||||
|
No whitespace before the open paren/bracket that starts an argument list,
|
||||||
|
indexing or slicing.
|
||||||
|
|
||||||
|
```python
|
||||||
|
Yes: spam(1)
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
No: spam (1)
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
Yes: dict['key'] = list[index]
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
No: dict ['key'] = list [index]
|
||||||
|
```
|
||||||
|
|
||||||
|
No trailing whitespace.
|
||||||
|
|
||||||
|
Surround binary operators with a single space on either side for assignment
|
||||||
|
(`=`), comparisons (`==, <, >, !=, <>, <=, >=, in, not in, is, is not`), and
|
||||||
|
Booleans (`and, or, not`). Use your better judgment for the insertion of spaces
|
||||||
|
around arithmetic operators (`+`, `-`, `*`, `/`, `//`, `%`, `**`, `@`).
|
||||||
|
|
||||||
|
```python
|
||||||
|
Yes: x == 1
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
No: x<1
|
||||||
|
```
|
||||||
|
|
||||||
|
Never use spaces around `=` when passing keyword arguments or defining a default
|
||||||
|
parameter value, with one exception:
|
||||||
|
[when a type annotation is present](#typing-default-values), *do* use spaces
|
||||||
|
around the `=` for the default parameter value.
|
||||||
|
|
||||||
|
```python
|
||||||
|
Yes: def complex(real, imag=0.0): return Magic(r=real, i=imag)
|
||||||
|
Yes: def complex(real, imag: float = 0.0): return Magic(r=real, i=imag)
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
No: def complex(real, imag = 0.0): return Magic(r = real, i = imag)
|
||||||
|
No: def complex(real, imag: float=0.0): return Magic(r = real, i = imag)
|
||||||
|
```
|
||||||
|
|
||||||
|
Don't use spaces to vertically align tokens on consecutive lines, since it
|
||||||
|
becomes a maintenance burden (applies to `:`, `#`, `=`, etc.):
|
||||||
|
|
||||||
|
```python
|
||||||
|
Yes:
|
||||||
|
foo = 1000 # comment
|
||||||
|
long_name = 2 # comment that should not be aligned
|
||||||
|
|
||||||
|
dictionary = {
|
||||||
|
'foo': 1,
|
||||||
|
'long_name': 2,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
No:
|
||||||
|
foo = 1000 # comment
|
||||||
|
long_name = 2 # comment that should not be aligned
|
||||||
|
|
||||||
|
dictionary = {
|
||||||
|
'foo' : 1,
|
||||||
|
'long_name': 2,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
<a id="Python_Interpreter"></a>
|
<a id="Python_Interpreter"></a>
|
||||||
<a id="s3.7-shebang-line"></a>
|
<a id="s3.7-shebang-line"></a>
|
||||||
|
@ -1929,15 +2076,6 @@ should use the same style as the docstring for an attribute or a
|
||||||
<a href="#doc-function-args">function argument</a> (`"""The Bigtable path."""`,
|
<a href="#doc-function-args">function argument</a> (`"""The Bigtable path."""`,
|
||||||
rather than `"""Returns the Bigtable path."""`).
|
rather than `"""Returns the Bigtable path."""`).
|
||||||
|
|
||||||
A method that overrides a method from a base class may have a simple docstring
|
|
||||||
sending the reader to its overridden method's docstring, such as `"""See base
|
|
||||||
class."""`. The rationale is that there is no need to repeat in many places
|
|
||||||
documentation that is already present in the base method's docstring. However,
|
|
||||||
if the overriding method's behavior is substantially different from the
|
|
||||||
overridden method, or details need to be provided (e.g., documenting additional
|
|
||||||
side effects), a docstring with at least those differences is required on the
|
|
||||||
overriding method.
|
|
||||||
|
|
||||||
Certain aspects of a function should be documented in special sections, listed
|
Certain aspects of a function should be documented in special sections, listed
|
||||||
below. Each section begins with a heading line, which ends with a colon. All
|
below. Each section begins with a heading line, which ends with a colon. All
|
||||||
sections other than the heading should maintain a hanging indent of two or four
|
sections other than the heading should maintain a hanging indent of two or four
|
||||||
|
@ -1961,16 +2099,18 @@ aptly described using a one-line docstring.
|
||||||
: Describe the semantics of the return value, including any type information
|
: Describe the semantics of the return value, including any type information
|
||||||
that the type annotation does not provide. If the function only returns
|
that the type annotation does not provide. If the function only returns
|
||||||
None, this section is not required. It may also be omitted if the docstring
|
None, this section is not required. It may also be omitted if the docstring
|
||||||
starts with Returns or Yields (e.g. `"""Returns row from Bigtable as a tuple
|
starts with "Return", "Returns", "Yield", or "Yields" (e.g. `"""Returns row
|
||||||
of strings."""`) and the opening sentence is sufficient to describe the
|
from Bigtable as a tuple of strings."""`) *and* the opening sentence is
|
||||||
return value. Do not imitate 'NumPy style'
|
sufficient to describe the return value. Do not imitate older 'NumPy style'
|
||||||
([example](http://numpy.org/doc/stable/reference/generated/numpy.linalg.qr.html)),
|
([example](https://numpy.org/doc/1.24/reference/generated/numpy.linalg.qr.html)),
|
||||||
which frequently documents a tuple return value as if it were multiple
|
which frequently documented a tuple return value as if it were multiple
|
||||||
return values with individual names (never mentioning the tuple). Instead,
|
return values with individual names (never mentioning the tuple). Instead,
|
||||||
describe such a return value as: "Returns: A tuple (mat_a, mat_b), where
|
describe such a return value as: "Returns: A tuple (mat_a, mat_b), where
|
||||||
mat_a is ..., and ...". The auxiliary names in the docstring need not
|
mat_a is ..., and ...". The auxiliary names in the docstring need not
|
||||||
necessarily correspond to any internal names used in the function body (as
|
necessarily correspond to any internal names used in the function body (as
|
||||||
those are not part of the API).
|
those are not part of the API). If the function uses `yield` (is a
|
||||||
|
generator), the `Yields:` section should document the object returned by
|
||||||
|
`next()`, instead of the generator object itself that the call evaluates to.
|
||||||
|
|
||||||
<a id="doc-function-raises"></a>
|
<a id="doc-function-raises"></a>
|
||||||
[*Raises:*](#doc-function-raises)
|
[*Raises:*](#doc-function-raises)
|
||||||
|
@ -2057,6 +2197,47 @@ def fetch_smalltable_rows(
|
||||||
"""
|
"""
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<a id="s3.8.3.1-overridden-methods"></a>
|
||||||
|
|
||||||
|
<a id="overridden-method-docs"></a>
|
||||||
|
##### 3.8.3.1 Overridden Methods
|
||||||
|
|
||||||
|
A method that overrides a method from a base class does not need a docstring if
|
||||||
|
it is explicitly decorated with
|
||||||
|
[`@override`](https://typing-extensions.readthedocs.io/en/latest/#override)
|
||||||
|
(from `typing_extensions` or `typing` modules), unless the overriding method's
|
||||||
|
behavior materially refines the base method's contract, or details need to be
|
||||||
|
provided (e.g., documenting additional side effects), in which case a docstring
|
||||||
|
with at least those differences is required on the overriding method.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from typing_extensions import override
|
||||||
|
|
||||||
|
class Parent:
|
||||||
|
def do_something(self):
|
||||||
|
"""Parent method, includes docstring."""
|
||||||
|
|
||||||
|
# Child class, method annotated with override.
|
||||||
|
class Child(Parent):
|
||||||
|
@override
|
||||||
|
def do_something(self):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Child class, but without @override decorator, a docstring is required.
|
||||||
|
class Child(Parent):
|
||||||
|
def do_something(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Docstring is trivial, @override is sufficient to indicate that docs can be
|
||||||
|
# found in the base class.
|
||||||
|
class Child(Parent):
|
||||||
|
@override
|
||||||
|
def do_something(self):
|
||||||
|
"""See base class."""
|
||||||
|
```
|
||||||
|
|
||||||
<a id="s3.8.4-comments-in-classes"></a>
|
<a id="s3.8.4-comments-in-classes"></a>
|
||||||
<a id="384-classes"></a>
|
<a id="384-classes"></a>
|
||||||
<a id="comments-in-classes"></a>
|
<a id="comments-in-classes"></a>
|
||||||
|
@ -2065,8 +2246,8 @@ def fetch_smalltable_rows(
|
||||||
#### 3.8.4 Classes
|
#### 3.8.4 Classes
|
||||||
|
|
||||||
Classes should have a docstring below the class definition describing the class.
|
Classes should have a docstring below the class definition describing the class.
|
||||||
If your class has public attributes, they should be documented here in an
|
Public attributes, excluding [properties](#properties), should be documented
|
||||||
`Attributes` section and follow the same formatting as a
|
here in an `Attributes` section and follow the same formatting as a
|
||||||
[function's `Args`](#doc-function-args) section.
|
[function's `Args`](#doc-function-args) section.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -2090,8 +2271,9 @@ class SampleClass:
|
||||||
self.likes_spam = likes_spam
|
self.likes_spam = likes_spam
|
||||||
self.eggs = 0
|
self.eggs = 0
|
||||||
|
|
||||||
def public_method(self):
|
@property
|
||||||
"""Performs operation blah."""
|
def butter_sticks(self) -> int:
|
||||||
|
"""The number of butter sticks we have."""
|
||||||
```
|
```
|
||||||
|
|
||||||
All class docstrings should start with a one-line summary that describes what
|
All class docstrings should start with a one-line summary that describes what
|
||||||
|
@ -2366,7 +2548,7 @@ messages shown to the user) should follow three guidelines:
|
||||||
```python
|
```python
|
||||||
Yes:
|
Yes:
|
||||||
if not 0 <= p <= 1:
|
if not 0 <= p <= 1:
|
||||||
raise ValueError(f'Not a probability: {p!r}')
|
raise ValueError(f'Not a probability: {p=}')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.rmdir(workdir)
|
os.rmdir(workdir)
|
||||||
|
@ -2378,7 +2560,7 @@ messages shown to the user) should follow three guidelines:
|
||||||
```python
|
```python
|
||||||
No:
|
No:
|
||||||
if p < 0 or p > 1: # PROBLEM: also false for float('nan')!
|
if p < 0 or p > 1: # PROBLEM: also false for float('nan')!
|
||||||
raise ValueError(f'Not a probability: {p!r}')
|
raise ValueError(f'Not a probability: {p=}')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.rmdir(workdir)
|
os.rmdir(workdir)
|
||||||
|
@ -2477,27 +2659,36 @@ documentation must explain clearly how resource lifetime is managed.
|
||||||
Use `TODO` comments for code that is temporary, a short-term solution, or
|
Use `TODO` comments for code that is temporary, a short-term solution, or
|
||||||
good-enough but not perfect.
|
good-enough but not perfect.
|
||||||
|
|
||||||
A `TODO` comment begins with the word `TODO` in all caps, and a parenthesized
|
A `TODO` comment begins with the word `TODO` in all caps, a following colon, and
|
||||||
context identifier. Ideally a bug reference, sometimes a username. A bug
|
a link to a resource that contains the context, ideally a bug reference. A bug
|
||||||
reference like `TODO(https://crbug.com/bug_id_number):` is
|
reference is preferable because bugs are tracked and have follow-up comments.
|
||||||
preferable, because bugs are tracked and have follow-up comments, whereas
|
Follow this piece of context with an explanatory string introduced with a hyphen
|
||||||
individuals move around and may lose context over time. The `TODO` is followed by an explanation of
|
`-`.
|
||||||
what there is to do.
|
|
||||||
|
|
||||||
The purpose is to have a consistent `TODO` format that can be searched to find
|
The purpose is to have a consistent `TODO` format that can be searched to find
|
||||||
out how to get more details. A `TODO` is not a commitment that the person
|
out how to get more details.
|
||||||
referenced will fix the problem. Thus when you create a `TODO` with a username,
|
|
||||||
it is almost always your *own* username that is given.
|
```python
|
||||||
|
# TODO: crbug.com/192795 - Investigate cpufreq optimizations.
|
||||||
|
```
|
||||||
|
|
||||||
|
Old style, formerly recommended, but discouraged for use in new code:
|
||||||
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# TODO(crbug.com/192795): Investigate cpufreq optimizations.
|
# TODO(crbug.com/192795): Investigate cpufreq optimizations.
|
||||||
# TODO(yourusername): File an issue and use a '*' for repetition.
|
# TODO(yourusername): Use a "\*" here for concatenation operator.
|
||||||
|
```
|
||||||
|
|
||||||
|
Avoid adding TODOs that refer to an individual or team as the context:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# TODO: @yourusername - File an issue and use a '*' for repetition.
|
||||||
```
|
```
|
||||||
|
|
||||||
If your `TODO` is of the form "At a future date do something" make sure that you
|
If your `TODO` is of the form "At a future date do something" make sure that you
|
||||||
either include a very specific date ("Fix by November 2009") or a very specific
|
either include a very specific date ("Fix by November 2009") or a very specific
|
||||||
event ("Remove this code when all clients can handle XML responses.") that
|
event ("Remove this code when all clients can handle XML responses.") that
|
||||||
future code maintainers will comprehend.
|
future code maintainers will comprehend. Issues are ideal for tracking this.
|
||||||
|
|
||||||
<a id="s3.13-imports-formatting"></a>
|
<a id="s3.13-imports-formatting"></a>
|
||||||
<a id="313-imports-formatting"></a>
|
<a id="313-imports-formatting"></a>
|
||||||
|
@ -2722,7 +2913,9 @@ Always use a `.py` filename extension. Never use dashes.
|
||||||
class.
|
class.
|
||||||
|
|
||||||
- Prepending a single underscore (`_`) has some support for protecting module
|
- Prepending a single underscore (`_`) has some support for protecting module
|
||||||
variables and functions (linters will flag protected member access).
|
variables and functions (linters will flag protected member access). Note
|
||||||
|
that it is okay for unit tests to access protected constants from the
|
||||||
|
modules under test.
|
||||||
|
|
||||||
- Prepending a double underscore (`__` aka "dunder") to an instance variable
|
- Prepending a double underscore (`__` aka "dunder") to an instance variable
|
||||||
or method effectively makes the variable or method private to its class
|
or method effectively makes the variable or method private to its class
|
||||||
|
@ -2930,13 +3123,20 @@ the function into smaller and more manageable pieces.
|
||||||
|
|
||||||
* Familiarize yourself with [PEP-484](https://peps.python.org/pep-0484/).
|
* Familiarize yourself with [PEP-484](https://peps.python.org/pep-0484/).
|
||||||
|
|
||||||
* In methods, only annotate `self`, or `cls` if it is necessary for proper
|
* Annotating `self` or `cls` is generally not necessary.
|
||||||
type information. e.g.,
|
[`Self`](https://docs.python.org/3/library/typing.html#typing.Self) can be
|
||||||
|
used if it is necessary for proper type information, e.g.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
from typing import Self
|
||||||
|
|
||||||
|
class BaseClass:
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls: Type[_T]) -> _T:
|
def create(cls) -> Self:
|
||||||
return cls()
|
...
|
||||||
|
|
||||||
|
def difference(self, other: Self) -> float:
|
||||||
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
* Similarly, don't feel compelled to annotate the return value of `__init__`
|
* Similarly, don't feel compelled to annotate the return value of `__init__`
|
||||||
|
@ -3327,15 +3527,16 @@ return type is the same as the argument type in the code above, use
|
||||||
<a id="typing-imports"></a>
|
<a id="typing-imports"></a>
|
||||||
#### 3.19.12 Imports For Typing
|
#### 3.19.12 Imports For Typing
|
||||||
|
|
||||||
For symbols from the `typing` and `collections.abc` modules used to support
|
For symbols (including types, functions, and constants) from the `typing` or
|
||||||
static analysis and type checking, always import the symbol itself. This keeps
|
`collections.abc` modules used to support static analysis and type checking,
|
||||||
common annotations more concise and matches typing practices used around the
|
always import the symbol itself. This keeps common annotations more concise and
|
||||||
world. You are explicitly allowed to import multiple specific classes on one
|
matches typing practices used around the world. You are explicitly allowed to
|
||||||
line from the `typing` and `collections.abc` modules. Ex:
|
import multiple specific symbols on one line from the `typing` and
|
||||||
|
`collections.abc` modules. For example:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from collections.abc import Mapping, Sequence
|
from collections.abc import Mapping, Sequence
|
||||||
from typing import Any, Generic
|
from typing import Any, Generic, cast, TYPE_CHECKING
|
||||||
```
|
```
|
||||||
|
|
||||||
Given that this way of importing adds items to the local namespace, names in
|
Given that this way of importing adds items to the local namespace, names in
|
||||||
|
|
40
pylintrc
40
pylintrc
|
@ -5,7 +5,7 @@
|
||||||
# Its canonical open-source location is:
|
# Its canonical open-source location is:
|
||||||
# https://google.github.io/styleguide/pylintrc
|
# https://google.github.io/styleguide/pylintrc
|
||||||
|
|
||||||
[MASTER]
|
[MAIN]
|
||||||
|
|
||||||
# Files or directories to be skipped. They should be base names, not paths.
|
# Files or directories to be skipped. They should be base names, not paths.
|
||||||
ignore=third_party
|
ignore=third_party
|
||||||
|
@ -50,7 +50,8 @@ confidence=
|
||||||
# --enable=similarities". If you want to run only the classes checker, but have
|
# --enable=similarities". If you want to run only the classes checker, but have
|
||||||
# no Warning level messages displayed, use"--disable=all --enable=classes
|
# no Warning level messages displayed, use"--disable=all --enable=classes
|
||||||
# --disable=W"
|
# --disable=W"
|
||||||
disable=abstract-method,
|
disable=R,
|
||||||
|
abstract-method,
|
||||||
apply-builtin,
|
apply-builtin,
|
||||||
arguments-differ,
|
arguments-differ,
|
||||||
attribute-defined-outside-init,
|
attribute-defined-outside-init,
|
||||||
|
@ -66,7 +67,6 @@ disable=abstract-method,
|
||||||
coerce-method,
|
coerce-method,
|
||||||
delslice-method,
|
delslice-method,
|
||||||
div-method,
|
div-method,
|
||||||
duplicate-code,
|
|
||||||
eq-without-hash,
|
eq-without-hash,
|
||||||
execfile-builtin,
|
execfile-builtin,
|
||||||
file-builtin,
|
file-builtin,
|
||||||
|
@ -80,7 +80,6 @@ disable=abstract-method,
|
||||||
import-error,
|
import-error,
|
||||||
import-self,
|
import-self,
|
||||||
import-star-module-level,
|
import-star-module-level,
|
||||||
inconsistent-return-statements,
|
|
||||||
input-builtin,
|
input-builtin,
|
||||||
intern-builtin,
|
intern-builtin,
|
||||||
invalid-str-codec,
|
invalid-str-codec,
|
||||||
|
@ -94,10 +93,6 @@ disable=abstract-method,
|
||||||
next-method-called,
|
next-method-called,
|
||||||
next-method-defined,
|
next-method-defined,
|
||||||
no-absolute-import,
|
no-absolute-import,
|
||||||
no-else-break,
|
|
||||||
no-else-continue,
|
|
||||||
no-else-raise,
|
|
||||||
no-else-return,
|
|
||||||
no-init, # added
|
no-init, # added
|
||||||
no-member,
|
no-member,
|
||||||
no-name-in-module,
|
no-name-in-module,
|
||||||
|
@ -123,24 +118,12 @@ disable=abstract-method,
|
||||||
standarderror-builtin,
|
standarderror-builtin,
|
||||||
suppressed-message,
|
suppressed-message,
|
||||||
sys-max-int,
|
sys-max-int,
|
||||||
too-few-public-methods,
|
|
||||||
too-many-ancestors,
|
|
||||||
too-many-arguments,
|
|
||||||
too-many-boolean-expressions,
|
|
||||||
too-many-branches,
|
|
||||||
too-many-instance-attributes,
|
|
||||||
too-many-locals,
|
|
||||||
too-many-nested-blocks,
|
|
||||||
too-many-public-methods,
|
|
||||||
too-many-return-statements,
|
|
||||||
too-many-statements,
|
|
||||||
trailing-newlines,
|
trailing-newlines,
|
||||||
unichr-builtin,
|
unichr-builtin,
|
||||||
unicode-builtin,
|
unicode-builtin,
|
||||||
unnecessary-pass,
|
unnecessary-pass,
|
||||||
unpacking-in-except,
|
unpacking-in-except,
|
||||||
useless-else-on-loop,
|
useless-else-on-loop,
|
||||||
useless-object-inheritance,
|
|
||||||
useless-suppression,
|
useless-suppression,
|
||||||
using-cmp-argument,
|
using-cmp-argument,
|
||||||
wrong-import-order,
|
wrong-import-order,
|
||||||
|
@ -225,7 +208,7 @@ no-docstring-rgx=(__.*__|main|test.*|.*test|.*Test)$
|
||||||
|
|
||||||
# Minimum line length for functions/classes that require docstrings, shorter
|
# Minimum line length for functions/classes that require docstrings, shorter
|
||||||
# ones are exempt.
|
# ones are exempt.
|
||||||
docstring-min-length=10
|
docstring-min-length=12
|
||||||
|
|
||||||
|
|
||||||
[TYPECHECK]
|
[TYPECHECK]
|
||||||
|
@ -235,10 +218,6 @@ docstring-min-length=10
|
||||||
# produce valid context managers.
|
# produce valid context managers.
|
||||||
contextmanager-decorators=contextlib.contextmanager,contextlib2.contextmanager
|
contextmanager-decorators=contextlib.contextmanager,contextlib2.contextmanager
|
||||||
|
|
||||||
# Tells whether missing members accessed in mixin class should be ignored. A
|
|
||||||
# mixin class is detected if its name ends with "mixin" (case insensitive).
|
|
||||||
ignore-mixin-members=yes
|
|
||||||
|
|
||||||
# List of module names for which member attributes should not be checked
|
# List of module names for which member attributes should not be checked
|
||||||
# (useful for modules/projects where namespaces are manipulated during runtime
|
# (useful for modules/projects where namespaces are manipulated during runtime
|
||||||
# and thus existing member attributes cannot be deduced by static analysis. It
|
# and thus existing member attributes cannot be deduced by static analysis. It
|
||||||
|
@ -261,7 +240,7 @@ generated-members=
|
||||||
# Maximum number of characters on a single line.
|
# Maximum number of characters on a single line.
|
||||||
max-line-length=80
|
max-line-length=80
|
||||||
|
|
||||||
# TODO(https://github.com/PyCQA/pylint/issues/3352): Direct pylint to exempt
|
# TODO(https://github.com/pylint-dev/pylint/issues/3352): Direct pylint to exempt
|
||||||
# lines made too long by directives to pytype.
|
# lines made too long by directives to pytype.
|
||||||
|
|
||||||
# Regexp for a line that is allowed to be longer than the limit.
|
# Regexp for a line that is allowed to be longer than the limit.
|
||||||
|
@ -418,12 +397,3 @@ valid-classmethod-first-arg=cls,
|
||||||
|
|
||||||
# List of valid names for the first argument in a metaclass class method.
|
# List of valid names for the first argument in a metaclass class method.
|
||||||
valid-metaclass-classmethod-first-arg=mcs
|
valid-metaclass-classmethod-first-arg=mcs
|
||||||
|
|
||||||
|
|
||||||
[EXCEPTIONS]
|
|
||||||
|
|
||||||
# Exceptions that will emit a warning when being caught. Defaults to
|
|
||||||
# "Exception"
|
|
||||||
overgeneral-exceptions=builtins.StandardError,
|
|
||||||
builtins.Exception,
|
|
||||||
builtins.BaseException
|
|
||||||
|
|
|
@ -7,7 +7,13 @@ body {
|
||||||
margin-left: 100px;
|
margin-left: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6, .toc_title {
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6,
|
||||||
|
.toc_title {
|
||||||
color: #06c;
|
color: #06c;
|
||||||
margin-top: 2em;
|
margin-top: 2em;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
|
@ -18,38 +24,47 @@ h1 {
|
||||||
font-size: 18pt;
|
font-size: 18pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2, .toc_title {
|
h2,
|
||||||
|
.toc_title {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 12pt;
|
font-size: 12pt;
|
||||||
margin-left: -40px;
|
margin-left: -40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3, h4, h5, h6 {
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
margin-left: -20px;
|
margin-left: -20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toc_category, .toc_stylepoint {
|
.toc_category,
|
||||||
|
.toc_stylepoint {
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
padding-top: .3em;
|
padding-top: 0.3em;
|
||||||
padding-bottom: .3em;
|
padding-bottom: 0.3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
|
|
||||||
td, th {
|
td,
|
||||||
|
th {
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
padding: 2px 12px;
|
padding: 2px 12px;
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toc td, .toc th {
|
.toc td,
|
||||||
|
.toc th {
|
||||||
border-width: 1px 5px;
|
border-width: 1px 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
code, samp, var {
|
code,
|
||||||
|
samp,
|
||||||
|
var {
|
||||||
color: #060;
|
color: #060;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,16 +73,9 @@ pre {
|
||||||
display: block;
|
display: block;
|
||||||
color: #060;
|
color: #060;
|
||||||
background-color: #f8fff8;
|
background-color: #f8fff8;
|
||||||
border-color: #f0fff0;
|
border: 1px solid #f0fff0;
|
||||||
border-style: solid;
|
|
||||||
border-top-width: 1px;
|
|
||||||
border-bottom-width: 1px;
|
|
||||||
border-right-width: 1px;
|
|
||||||
border-left-width: 5px;
|
border-left-width: 5px;
|
||||||
padding-left: 12px;
|
padding: 4px 12px;
|
||||||
padding-right: 12px;
|
|
||||||
padding-top: 4px;
|
|
||||||
padding-bottom: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pre.badcode {
|
pre.badcode {
|
||||||
|
@ -79,8 +87,7 @@ pre.badcode {
|
||||||
.showhide_button {
|
.showhide_button {
|
||||||
float: left;
|
float: left;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-width: 1px;
|
border: 1px solid;
|
||||||
border-style: solid;
|
|
||||||
border-color: #ddd #aaa #aaa #ddd;
|
border-color: #ddd #aaa #aaa #ddd;
|
||||||
padding: 0 3px 1px;
|
padding: 0 3px 1px;
|
||||||
margin: 0 4px 8px 0;
|
margin: 0 4px 8px 0;
|
||||||
|
@ -93,9 +100,7 @@ pre.badcode {
|
||||||
float: left;
|
float: left;
|
||||||
display: none;
|
display: none;
|
||||||
background-color: #f8f8ff;
|
background-color: #f8f8ff;
|
||||||
border-color: #f0f0ff;
|
border: 1px solid #f0f0ff;
|
||||||
border-style: solid;
|
|
||||||
border-width: 1px;
|
|
||||||
font-size: 75%;
|
font-size: 75%;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-left: -50px;
|
margin-left: -50px;
|
||||||
|
@ -118,7 +123,7 @@ hr {
|
||||||
.stylepoint_section {
|
.stylepoint_section {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
color: #5588ff;
|
color: #58f;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
@ -126,7 +131,7 @@ hr {
|
||||||
}
|
}
|
||||||
|
|
||||||
.stylepoint_subsection {
|
.stylepoint_subsection {
|
||||||
color: #667799;
|
color: #679;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
@ -134,7 +139,7 @@ hr {
|
||||||
}
|
}
|
||||||
|
|
||||||
.stylepoint_subsubsection {
|
.stylepoint_subsubsection {
|
||||||
color: #667799;
|
color: #679;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
@ -144,4 +149,3 @@ hr {
|
||||||
.revision {
|
.revision {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
4353
tsguide.html
4353
tsguide.html
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user