Is there a way to get the string value out of a KeySym value?
For example, out of keyPrintable("a").
If you know the KeySym value is a keyPrintable, you can just get it using the key property. For instance
KeySym kv = ... // something that yields a KeySym
str s = kv.key;
If you don't know it's a keyPrintable you can either check to see if it was built using that constructor, or use pattern matching. So, either
if (kv is keyPrintable) {
// code that uses kv.key to get back the value
}
or
if (keyPrintable(str s) := kv) {
// code that can now use s, which is the key
}
You can also ask if kv has that field, and then use it:
if (kv has key) {
// code that uses kv.key
}
Once you introduce a field name in a constructor, and it has a specific type, you know that same field name has that same type in any additional constructors for the same datatype. So, once we know field key is type str, field key has to be str in any value of type KeySym. That is why it's fine to see if kv has field key and then treat it as a str, nobody could come along later and add a new constructor for KeySym where key has a different type.
Related
For simple data types, you can use e.g.
object is String
to check whether an Object variable is of a more specific type.
But let's you have a List, but want to check if it is a List of Strings. Intuitively we might try
List list = ['string', 'other string'];
print(list is List<String>);
which returns false.
Similarly using the List.cast() method doesn't help, it will always succeed and only throw an error later on when using the list.
We could iterate over the entire list and check the type of each individual entry, but I was hoping there might be a better way.
There is no other way. What you have is a List<Object?>/List<dynamic> (because the type is inferred from the variable type, which is a raw List type which gets instantiated to its bound). The list currently only contains String objects, but nothing prevents you from adding a new Object() to it.
So, the object itself doesn't know that it only contains strings, you have to look at each element to check that.
Or, when you create a list, just declare the variable as List<String> list = ...; or var list = ...;, then the object will be a List<String>.
If you are not the one creating the list, it's back to list.every((e) => e is String).
Each element of a List may be of any type BUT IF YOU ARE SURE that all elements have the same type this approach may be useful
bool listElementIs<T>(List l) {
if (l.isEmpty) return true;
try {
if (l[0] is T) return true; // only try to access to check element
} catch (e) {
return false;
}
return false;
}
void main() {
List list = ['string', 'other string'];
print(listElementIs<String>(list)); // prints 'true'
print(listElementIs<int>(list)); // prints 'false'
}
I think a better way to do this is to be specific about your data types.
By specifying the types of variables, you can catch potential errors early on during the development process.
In addition, specifying the types of variables makes the code more readable and understandable.
Furthermore, specifying types can also improve the performance of your code, as the compiler can make certain optimizations based on the types of variables.
List<String> list = <String>['string', 'other string'];
print(list is List<String>); /// prints true.
You can use this linter rule to enforce it:
https://dart-lang.github.io/linter/lints/always_specify_types.html
Given a Map variable, how can I determine the type of Key and Value from it?
For example:
void doSomething(Map m){
print('m: ${m.runtimeType}');
print('keys: ${m.keys.runtimeType}');
print('values: ${m.values.runtimeType}');
print('entries: ${m.entries.runtimeType}');
}
void main() async {
Map<String, int> m = {};
doSomething(m);
}
This will print
m: _InternalLinkedHashMap<String, int>
keys: _CompactIterable<String>
values: _CompactIterable<int>
entries: MappedIterable<String, MapEntry<String, int>>
But how can I get the actual type of Key and Value (i.e. String and int), so that I can use them in type checking code (i.e. if( KeyType == String ))?
You cannot extract the type parameters of a class if it doesn't provide them to you, and Map does not.
An example of a class which does provide them is something like:
class Example<T> {
Type get type => T;
R withType<R>(R Function<X>() callback) => callback<T>();
}
If you have an instance of Example, you can get to the type parameter, either as a Type (which is generally useless), or as a type argument which allows you to do anything with the type.
Alas, providing access to types variables that way is very rare in most classes.
You can possibly use reflection if you have access to dart:mirrors, but most code does not (it doesn't work with ahead-of-time compilation, which includes all web code, or in Flutter programs).
You can try to guess the type by trying types that you know (like map is Map<dynamic, num>, then map is Map<dynamic, int> and map is Map<dynamic, Never>. If the first two are true, and the last one is false, then the value type is definitely int. That only works if you know all the possible types.
It does work particularly well for platform types like int and String because you know for certain that their only subtype is Never.
If you can depend on the static type instead of the runtime type, you could use a generic function:
Type mapKeyType<K, V>(Map<K, V> map) => K;
Otherwise you would need to have a non-empty Map and inspect the runtime types of the actual elements.
Given some nullable type T?, how do I get the corresponding non-nullable one T ?
For example:
T? x<T extends int?>(T? value) => value;
Type g<T>(T Function(T) t) => T;
Type type = g(x);
print(type); // Prints "int?"
Now I want to get the non-nullable type. How do I create the function convert so that:
Type nonNullableType = convert(type);
print(nonNullableType); // Prints "int"
If you have an instance of T?, and you're trying to do something where the expected type is T, you can use use T! wherever dart is showing an error. It is not exactly a conversion from T? to T, its just a shortcut to do a null check.
In general, you do not. There is no simple way to strip the ? of a type, or destructure types in other ways. (You also can't find the T of type you know is a List<T> at run--time)
If you have the type as a Type object, you can do nothing with it. Using Type object is almost never what you need.
If you have the type as a type parameter, then the type system don't actually know whether it's nullable. Example:
void foo<T>() { ... here T can be nullable or non-nullable ... }
Even if you test null is T to check that the type is actually nullable, the type system doesn't get any smarter, that's not one of the tests that it can derive type information from.
The only types you can improve on are variable types (or rather, the type of a single value currently stored in a variable). So, if you have T x = ...; and you do if (x != null) { ... x is not null here }, you can promote the variable to T&Object, but that's only an intermediate type to allow you to call members on the variable, it's not a real type that you can capture as a type variable or a variable type. It won't help you.
All in all, it can't be done. When you have the nullable type, it's too late, you need to capture it before adding the ?.
What problem are you actually trying to solve?
If you have an instance of T?, I think you could do:
Type nonNullableTypeOf<T>(T? object) => T;
void main() {
int x = 42;
int? y;
print(nonNullableTypeOf(x)); // Prints: int
print(nonNullableTypeOf(y)); // Prints: int
}
If you have only T? itself (the Type object), then I'm not confident that there's much you can do since what you can do with Type objects is very limited. (And given those limitations, it's not clear that nonNullableTypeOf ultimately would be very useful either.)
A related question: How do I check whether a generic type is nullable in Dart NNBD?
final dList = <dynamic> [];
final List<String> sList1 = dList; // fails (can't implicitly cast)
final sList2 = dList.cast<String>(); // works (needs manual casting)
dynamic dString = '';
final String sString1 = dString; // works
final sString2 = dString as String; // works
You can see the comments in the code part what I am talking about, it is difficult to point out the piece of code here in writing part, so I added them in the code part.
List fails to convert but other types like bool, int, String works with internal casting.
The point is that dList is a List<dynamic>. The type dynamic is a top type (a supertype of all other types), and it's reified (so you can test it at run time, as opposed to Java where type arguments are erased at run time). With cast you are creating a new object, instance of List<String>, so it's allowed to be the value of a variable of that type.
With dString you already have an instance of type String (because '' evaluates to such an instance), so the cast just verifies that this is indeed a String.
You can never use a cast in Dart to obtain an object whose type is different from the starting point, it will only check the type of the existing object (and confirm that the type is as required, or throw).
I am trying to extract the case-insensitive query parameter /staging/ec/23463/front-view-72768.jpg?angle=90&or=0x0&wd=400&ht=200 from the URL. When I try to convert the whole URL in lowercase it throws the following exception :
cannot use r.URL (type *url.URL) as type string in argument to strings.ToLower
I printed the value of URL which says underlying it stores all the query strings as map i.e. map[angle:[90] or:[0x0] wd:[400] ht:[200]]. Hence I will get the correct value using this r.URL.Query().Get("or") But if query string comes out Or. It will fail.
*URL.Query() returns a value of type url.Values, which is just a map[string][]string with a few extra methods.
Since URL values are by definition case-sensitive, you will have to access the map directly.
var query url.Values
for k, vs := range query {
if strings.ToLower(k) == "ok" {
// do something with vs
}
}
Try it on the playground: https://play.golang.org/p/7YVuxI3GO6X
cannot use r.URL (type *url.URL) as type string in argument to strings.ToLower
This is because you are passing ur.URL instead of string. Get the string from url through String() function.
url.String()